-
-
Notifications
You must be signed in to change notification settings - Fork 282
feat: Glossaries #3003
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Glossaries #3003
Conversation
b6ac50b
to
1bfd767
Compare
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the WalkthroughThis update introduces a comprehensive glossary feature, including backend entities, repositories, services, controllers, DTOs, HATEOAS models, and extensive test coverage. New endpoints allow organizations to manage glossaries, terms, and translations, with role-based permissions and feature toggling. Supporting infrastructure (database schema, utility functions, OpenAPI docs) and machine translation integration are also included. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant API
participant GlossaryController
participant GlossaryService
participant GlossaryRepository
participant ProjectService
User->>API: HTTP POST /v2/organizations/{orgId}/glossaries
API->>GlossaryController: create(organizationId, dto)
GlossaryController->>GlossaryService: create(organization, dto)
GlossaryService->>ProjectService: findAll(dto.assignedProjectIds)
GlossaryService->>GlossaryRepository: save(new Glossary)
GlossaryService-->>GlossaryController: Glossary
GlossaryController-->>API: GlossaryModel
API-->>User: Response (Glossary created)
sequenceDiagram
participant User
participant API
participant GlossaryTermController
participant GlossaryTermService
participant GlossaryTermRepository
User->>API: HTTP POST /v2/organizations/{orgId}/glossaries/{glossaryId}/terms
API->>GlossaryTermController: create(organizationId, glossaryId, dto)
GlossaryTermController->>GlossaryTermService: createWithTranslation(organizationId, glossaryId, dto)
GlossaryTermService->>GlossaryTermRepository: save(new GlossaryTerm)
GlossaryTermService-->>GlossaryTermController: (GlossaryTerm, Translation)
GlossaryTermController-->>API: CreateUpdateGlossaryTermResponse
API-->>User: Response (Glossary term created)
sequenceDiagram
participant User
participant API
participant GlossaryTermHighlightsController
participant GlossaryTermService
User->>API: POST /v2/projects/{projectId}/glossary-highlights
API->>GlossaryTermHighlightsController: getHighlights(dto)
GlossaryTermHighlightsController->>GlossaryTermService: getHighlights(orgId, projectId, text, languageTag)
GlossaryTermService-->>GlossaryTermHighlightsController: Set<GlossaryTermHighlight>
GlossaryTermHighlightsController-->>API: CollectionModel<GlossaryTermHighlightModel>
API-->>User: Response (Highlights)
Suggested labels
Poem
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
e4846cf
to
81aa318
Compare
33d4b96
to
19c8f9e
Compare
7eb3a67
to
0487aaa
Compare
0487aaa
to
8ee8c4f
Compare
b58d617
to
872dda5
Compare
ad7633a
to
1eebc2d
Compare
@coderabbitai review |
✅ Actions performedReview triggered.
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 42
🔭 Outside diff range comments (1)
webapp/src/service/apiSchema.generated.ts (1)
8153-8179
: 🛠️ Refactor suggestion
unknown
response bodies hinder type-safetySeveral destructive/side‐effect endpoints (
delete_11
,delete_12
,deleteMultiple
, etc.) returnThis defeats the purpose of generated typings – frontend code must cast manually. Prefer:
description: No Contentor a small typed payload (
{ success: boolean }
). Update the OpenAPI spec so the generator emits a meaningful type (e.g.void
).
♻️ Duplicate comments (7)
webapp/src/ee/glossary/hooks/GlossaryContext.tsx (1)
14-19
: Component naming is misleading.The component name
GlossaryContext
suggests a simple context provider, but it's actually a data fetching component. This aligns with past reviewer feedback suggesting this approach might be overkill.Consider renaming to
GlossaryDataProvider
orGlossaryLoader
to better reflect its purpose, or simplify to a standard context provider as suggested by previous reviewers.webapp/src/ee/glossary/components/GlossaryViewLanguageSelect.tsx (2)
102-123
: 🛠️ Refactor suggestionExtract complex default value calculation logic.
This effect contains complex logic for calculating default values that would benefit from extraction into a well-named helper function, addressing the previous review feedback about method complexity.
+const calculateDefaultLanguageSelection = ( + glossaryLanguageTags: string[], + organizationLanguageTags: string[] +): string[] => { + const uniqueOrganizationLanguageTags = organizationLanguageTags.filter( + (l) => !glossaryLanguageTags.includes(l) + ); + return [...glossaryLanguageTags, ...uniqueOrganizationLanguageTags]; +}; useEffect(() => { if ( value === undefined && glossaryLanguagesLoadable.data && organizationLanguagesLoadable.data ) { - // Calculate and set default value const glossaryLanguageTags = getGlossaryLanguageTags(); const organizationLanguageTags = getFirstPageOfOrganizationLanguageTags(); - const uniqueOrganizationLanguageTags = organizationLanguageTags.filter( - (l) => !glossaryLanguageTags.includes(l) - ); - onValueChange([ - ...glossaryLanguageTags, - ...uniqueOrganizationLanguageTags, - ]); + onValueChange( + calculateDefaultLanguageSelection(glossaryLanguageTags, organizationLanguageTags) + ); } }, [
133-161
: 🛠️ Refactor suggestionExtract language merging logic into helper functions.
The
languages
useMemo contains complex logic for merging and transforming language data that would benefit from extraction into smaller, well-named functions.+const transformGlossaryLanguages = ( + glossaryLanguages: any[] +): OrganizationLanguageModel[] => { + const glossaryLanguagesBaseFirst = toSortedBaseFirst(glossaryLanguages); + return glossaryLanguagesBaseFirst.map((l) => { + const languageData = languageInfo[l.tag]; + return { + base: l.base, + tag: l.tag, + flagEmoji: languageData?.flags?.[0] || '', + originalName: languageData?.originalName || l.tag, + name: languageData?.englishName || l.tag, + }; + }); +}; + +const transformOrganizationLanguages = ( + organizationLanguages: OrganizationLanguageModel[], + glossaryLanguages: any[] +): OrganizationLanguageModel[] => { + const uniqueOrganizationLanguages = organizationLanguages.filter( + (l) => !glossaryLanguages.some((pl) => pl.tag === l.tag) + ); + const organizationLanguagesBaseFirst = toSortedBaseFirst( + uniqueOrganizationLanguages + ); + return organizationLanguagesBaseFirst.map((l) => ({ ...l, base: false })); +}; const languages: OrganizationLanguageModel[] = useMemo(() => { - // List of all glossary and organization languages - const glossaryLanguages = glossaryLanguagesLoadable.data?._embedded?.glossaryLanguageDtoList ?? []; - const glossaryLanguagesBaseFirst = toSortedBaseFirst(glossaryLanguages); - const glossaryLanguagesValue = glossaryLanguagesBaseFirst.map((l) => { - const languageData = languageInfo[l.tag]; - return { - base: l.base, - tag: l.tag, - flagEmoji: languageData?.flags?.[0] || '', - originalName: languageData?.originalName || l.tag, - name: languageData?.englishName || l.tag, - }; - }); - - const uniqueOrganizationLanguages = organizationLanguages.filter( - (l) => !glossaryLanguages.some((pl) => pl.tag === l.tag) - ); - const organizationLanguagesBaseFirst = toSortedBaseFirst( - uniqueOrganizationLanguages - ); - const organizationLanguagesValue = organizationLanguagesBaseFirst.map( - (l) => ({ ...l, base: false }) - ); - - return [...glossaryLanguagesValue, ...organizationLanguagesValue]; + const glossaryLanguagesValue = transformGlossaryLanguages(glossaryLanguages); + const organizationLanguagesValue = transformOrganizationLanguages( + organizationLanguages, + glossaryLanguages + ); + return [...glossaryLanguagesValue, ...organizationLanguagesValue]; }, [glossaryLanguagesLoadable.data, organizationLanguages]);webapp/src/ee/glossary/components/GlossaryBatchToolbar.tsx (1)
29-29
: Address the hardcoded margin-left valueThe hardcoded
margin-left: 5
spacing is still present as discussed in previous reviews. Consider using a more dynamic approach based on the layout context.e2e/cypress/compounds/glossaries/E2GlossaryView.ts (2)
44-55
: 🛠️ Refactor suggestionImprove selector robustness for translation editing.
Similar to the previous comment, the
:contains()
selector here could match unintended elements.- setTranslation(current: string, translation: string | undefined) { - gcy('glossary-translation-cell').filter(`:contains(${current})`).click(); + setTranslation(current: string, translation: string | undefined) { + // Escape special characters for jQuery :contains selector + const escapedCurrent = current.replace(/([\\!"#$%&'()*+,.\/:;<=>?@[\]^`{|}~])/g, '\\$1'); + gcy('glossary-translation-cell').filter(`:contains("${escapedCurrent}")`).click();
71-77
: 🛠️ Refactor suggestionExtract common pattern for selector-based filtering.
The same
:contains()
pattern is repeated multiple times. Consider extracting it to a helper method.Add a helper method to encapsulate the filtering logic:
private findTermListItem(termDefaultTranslationOrDescription: string) { const escapedText = termDefaultTranslationOrDescription.replace(/([\\!"#$%&'()*+,.\/:;<=>?@[\]^`{|}~])/g, '\\$1'); return gcy('glossary-term-list-item').filter(`:contains("${escapedText}")`); }Then update the methods:
- toggleTermChecked(termDefaultTranslationOrDescription: string) { - gcy('glossary-term-list-item') - .filter(`:contains(${termDefaultTranslationOrDescription})`) - .find('input[type="checkbox"]') - .click(); - } + toggleTermChecked(termDefaultTranslationOrDescription: string) { + this.findTermListItem(termDefaultTranslationOrDescription) + .find('input[type="checkbox"]') + .click(); + } - openEditTermDialog(termDefaultTranslationOrDescription: string) { - gcy('glossary-term-list-item') - .filter(`:contains(${termDefaultTranslationOrDescription})`) - .click(); - gcy('create-glossary-term-dialog').should('be.visible'); - return new E2GlossaryTermCreateEditDialog(); - } + openEditTermDialog(termDefaultTranslationOrDescription: string) { + this.findTermListItem(termDefaultTranslationOrDescription).click(); + gcy('create-glossary-term-dialog').should('be.visible'); + return new E2GlossaryTermCreateEditDialog(); + }webapp/src/views/projects/translations/translationVisual/TranslationWithPlaceholders.tsx (1)
29-83
: 🛠️ Refactor suggestionConsider extracting glossary highlight logic into a separate component as previously suggested.
JanCizmar previously suggested separating the glossary placeholder logic into a separate component. The current implementation mixes concerns of placeholder rendering and glossary highlighting, making the component complex and harder to test.
Consider creating a separate component or hook to handle glossary highlight logic:
// useModifiers.ts export function useModifiers( placeholders: Placeholder[], highlights: GlossaryTermHighlightModel[] ): Modifier[] { return useMemo(() => sortModifiers(placeholders, highlights), [placeholders, highlights]); } // Move sortModifiers and related functions to a separate utility file // glossaryUtils.ts export function sortModifiers( placeholders: Placeholder[], highlights: GlossaryTermHighlightModel[] ): Modifier[] { // ... existing implementation }This would improve testability and separation of concerns.
🧹 Nitpick comments (43)
webapp/src/component/layout/SecondaryBar.tsx (1)
10-10
: Consider adding JSDoc documentation for the new prop.The
reducedSpacing
prop would benefit from documentation explaining when and why to use it, especially since it's part of a shared layout component.+ /** When true, removes margin and top padding for tighter layouts */ reducedSpacing?: boolean;
webapp/src/component/layout/BaseViewWidth.ts (2)
8-8
: Improve type safety for string keys.The current type definition allows any string, not just valid keys from
widthMap
. Consider constraining it to only valid keys for better type safety.-export type BaseViewWidth = keyof typeof widthMap | number | undefined; +export type BaseViewWidth = keyof typeof widthMap | number | undefined;Actually, the current implementation is already correct! The
keyof typeof widthMap
properly constrains string values to only valid keys.
10-12
: Consider adding input validation or documentation.The function correctly handles the type conversion logic. However, consider documenting the behavior when an invalid string key is passed (returns undefined) or adding runtime validation if needed.
+/** + * Converts a BaseViewWidth to a numeric width value. + * @param width - Either a predefined width key, numeric value, or undefined + * @returns The corresponding numeric width or undefined for 'max' and invalid keys + */ export function getBaseViewWidth(width: BaseViewWidth) { return typeof width === 'string' ? widthMap[width] : width; }webapp/src/component/common/form/fields/SearchField.tsx (1)
28-33
: Consider moving the ref assignment into a useEffect for better performance.The current implementation assigns the clear callback on every render. Consider wrapping this in a
useEffect
to avoid unnecessary work:- if (clearCallbackRef !== undefined) { - clearCallbackRef.current = () => { - setSearch(''); - onSearch?.(''); - }; - } + useEffect(() => { + if (clearCallbackRef !== undefined) { + clearCallbackRef.current = () => { + setSearch(''); + onSearch?.(''); + }; + } + }, [clearCallbackRef, onSearch]);webapp/src/ee/glossary/hooks/useSelectedGlossaryLanguages.ts (1)
4-21
: Consider adding early return for better robustness.While the null checking fix above addresses the immediate issue, consider adding an early return when glossary is not available for better error handling.
export const useSelectedGlossaryLanguages = () => { const glossary = useGlossary(); + if (!glossary) { + return [undefined, () => {}] as const; + } const [selected, setSelected] = useState<string[] | undefined>(undefined); // ... rest of the hookwebapp/src/ee/glossary/components/GlossaryTermCreateEditFields.tsx (1)
1-1
: Consider using FC instead of VFC.
VFC
(VoidFunctionComponent) is deprecated in favor ofFC
(FunctionComponent) in newer React versions.-import { VFC } from 'react'; +import { FC } from 'react';-export const GlossaryTermCreateEditFields: VFC = () => { +export const GlossaryTermCreateEditFields: FC = () => {webapp/src/ee/glossary/views/GlossaryTermCreateDialog.tsx (1)
37-62
: Consider adding error handling for the mutation.The mutation currently only handles success cases. Consider adding error handling to provide user feedback when the operation fails.
const save = async (values: CreateOrUpdateGlossaryTermRequest) => { mutation.mutate( { path: { organizationId: preferredOrganization!.id, glossaryId: glossary.id, }, content: { 'application/json': values, }, }, { onSuccess() { messageService.success( <T keyName="glossary_term_create_success_message" /> ); onFinished(); }, + onError(error) { + messageService.error( + <T keyName="glossary_term_create_error_message" /> + ); + }, } ); };webapp/src/ee/glossary/hooks/useGlossaryTermHighlights.ts (1)
38-42
: Simplify conditional logic.The same conditions are checked both in the API query's
enabled
option and in this return statement. Consider consolidating the logic.- if (!glossaryFeature || !hasText || !enabled || !highlights.data) { + if (!highlights.data) { return []; } return highlights.data._embedded?.glossaryHighlights ?? [];The feature flag and text validation are already handled by the
enabled
option in the query, making this check redundant.webapp/src/ee/glossary/components/GlossariesPanel.tsx (1)
62-83
: Consider performance optimization for duplicate filtering.The current approach uses array filtering with
includes()
which has O(n²) complexity. For better performance with larger datasets, consider using a Set.- const found: number[] = []; + const found = new Set<number>(); const previews = terms .map((v) => v.value) .filter((term) => { - if (found.includes(term.id)) { + if (found.has(term.id)) { return false; } - found.push(term.id); + found.add(term.id); return true; })webapp/src/ee/glossary/components/GlossaryListItem.tsx (1)
82-91
: Overly complex language array creation.Creating a full language object structure for displaying a single language seems unnecessarily complex. This could be simplified since you're only showing the base language.
Consider simplifying this to just pass the necessary data directly to
CircledLanguageIconList
or create a simpler structure:- const languages = [ - { - base: true, - flagEmoji: languageData?.flags?.[0] || '', - id: 0, - name: languageData?.englishName || languageTag, - originalName: languageData?.originalName || languageTag, - tag: languageTag, - }, - ]; + const language = { + flagEmoji: languageData?.flags?.[0] || '', + name: languageData?.englishName || languageTag, + tag: languageTag, + };webapp/src/ee/glossary/components/GlossaryEmptyListMessage.tsx (2)
82-88
: Remove hidden elements from DOM.Using
visibility: 'hidden'
keeps the element in the DOM and affects layout, which is not ideal for accessibility and performance.Consider conditional rendering instead:
- <Link - href="https://docs.tolgee.io/platform/projects_and_organizations/glossary" - sx={{ visibility: 'hidden' }} - > - <Typography variant="body2"> - <T keyName="glossary_empty_placeholder_add_term_best_practices" /> - </Typography> - </Link> + {/* TODO: Uncomment when best practices content is ready */} + {false && ( + <Link href="https://docs.tolgee.io/platform/projects_and_organizations/glossary"> + <Typography variant="body2"> + <T keyName="glossary_empty_placeholder_add_term_best_practices" /> + </Typography> + </Link> + )}
90-112
: Hidden import card suggests incomplete feature.The entire import card is hidden with
display: 'none'
, suggesting this feature is not ready for release.Consider removing this card entirely until the import feature is implemented, or make it conditional based on a feature flag:
- <StyledCard elevation={0} sx={{ display: 'none' }}> + {/* TODO: Implement import functionality */} + {false && ( + <StyledCard elevation={0}> <StyledUploadCloud02 /> ... - </StyledCard> + </StyledCard> + )}webapp/src/ee/glossary/components/GlossaryTermCreateEditForm.tsx (3)
16-18
: Improve type intersection pattern.The type intersection creates a union of both request types, which may include conflicting properties. Consider using a more explicit approach or ensure the schemas are designed to be safely intersected.
-export type CreateOrUpdateGlossaryTermRequest = - CreateGlossaryTermWithTranslationRequest & - UpdateGlossaryTermWithTranslationRequest; +export type CreateOrUpdateGlossaryTermRequest = + | CreateGlossaryTermWithTranslationRequest + | UpdateGlossaryTermWithTranslationRequest;
25-25
: Consider more responsive width calculation.The fixed width calculation
min(calc(100vw - 64px), 600px)
uses magic numbers and may not work well across all viewport sizes and orientations.- width: min(calc(100vw - 64px), 600px); + width: min(calc(100vw - ${({ theme }) => theme.spacing(8)}), 600px); + max-width: 100%;
59-65
: Enhance loading state clarity.The undefined check for
initialValues
could be more explicit about the loading intent and consider handling potential error states.- if (initialValues === undefined) { + if (!initialValues) { return ( <StyledLoading> <SpinnerProgress /> </StyledLoading> ); }webapp/src/ee/glossary/hooks/useGlossaryTerms.ts (1)
26-28
: Consider making pagination configuration configurable.Hard-coded values for page size and sort order reduce flexibility and reusability of the hook.
+type Props = { + search: string | undefined; + languageTags: string[] | undefined; + pageSize?: number; + sortOrder?: string[]; +}; -export const useGlossaryTerms = ({ search, languageTags }: Props) => { +export const useGlossaryTerms = ({ + search, + languageTags, + pageSize = 30, + sortOrder = ['id,desc'] +}: Props) => { // ... const query = { search, languageTags, - size: 30, - sort: ['id,desc'], + size: pageSize, + sort: sortOrder, };webapp/src/component/searchSelect/InfiniteSearchSelect.tsx (2)
93-94
: Use optional chaining for cleaner code.The static analysis tool correctly identified that this can be simplified using optional chaining.
- onSearchChange && onSearchChange(''); + onSearchChange?.('');🧰 Tools
🪛 Biome (1.9.4)
[error] 93-93: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
145-145
: Consider safer access to anchorEl.current.The non-null assertion could throw if
anchorEl.current
is unexpectedly null. While this is likely safe given the context, consider defensive programming.- anchorEl={anchorEl.current!} + anchorEl={anchorEl.current ?? undefined}webapp/src/ee/glossary/components/GlossaryViewLanguageSelect.tsx (1)
44-51
: Add error handling for API queries.Consider adding error handling for the API queries to provide better user experience when data fetching fails.
if (glossaryLanguagesLoadable.error || organizationLanguagesLoadable.error) { // Handle error state - show error message or fallback UI }Also applies to: 62-88
webapp/src/ee/glossary/components/ScrollArrows.tsx (3)
8-8
: Consider making the arrow size configurable.The hardcoded
ARROW_SIZE
constant might not work well across different screen sizes and use cases. Consider making this configurable via props.
81-89
: Make scroll distance responsive and configurable.The hardcoded 350px scroll distance isn't responsive and may not work well on different screen sizes or content layouts.
Consider making the scroll distance dynamic:
const handleScroll = (direction: 'left' | 'right') => { const element = verticalScrollRef.current; if (element) { const position = element.scrollLeft; + const scrollDistance = Math.min(350, element.clientWidth * 0.8); element.scrollTo({ - left: position + (direction === 'left' ? -350 : +350), + left: position + (direction === 'left' ? -scrollDistance : +scrollDistance), }); } };
91-93
: Document the minimal height requirement.The
hasMinimalHeight
check silently hides the component below 400px height. Consider documenting this behavior or making it configurable.Add a comment explaining the rationale:
+ // Hide scroll arrows on very small screens where they would interfere with content if (!hasMinimalHeight) { return null; }
e2e/cypress/e2e/glossary/navigation.cy.ts (1)
35-44
: Consider testing Member access with Member organization data.Both tests use the Owner organization data. For proper Member role testing, consider using organization data where the user is a Member.
const testItself = () => { - const slug = getOrganizationByNameFromTestData(data, 'Owner').slug; + const orgName = cy.state('loginRole') === 'Member' ? 'Member' : 'Owner'; + const slug = getOrganizationByNameFromTestData(data, orgName).slug; cy.visit(`${HOST}/organizations/${slug}/profile`); gcy('settings-menu-item').filter(':contains("Glossaries")').click();Or create separate test functions for each role if the access patterns differ significantly.
webapp/src/ee/glossary/components/GlossaryBaseLanguageSelect.tsx (2)
38-39
: Document the error handling workaround.The comment indicates a schema issue but the workaround handles it properly. Consider adding more context about when this occurs.
- // Formik returns error as object - schema is incorrect... + // Formik returns error as nested object when using Yup schema validation + // Extract the specific field error from the error object const error = (meta.error as any)?.tag;
120-139
: Consider adding loading state indication.The component doesn't show any loading state while fetching data, which could lead to a poor user experience during slow network conditions.
Consider passing the loading state to the
InfiniteSearchSelect
:<InfiniteSearchSelect items={data} selected={value} queryResult={dataLoadable} + loading={dataLoadable.isLoading} itemKey={(item) => item.tag} search={search} onClearSelected={() => setValue(undefined)} onSearchChange={setSearch} onFetchMore={handleFetchMore} renderItem={renderItem} labelItem={labelItem} label={t('create_glossary_field_base_language')} error={meta.touched && error} searchPlaceholder={t('language_search_placeholder')} disabled={disabled} />
webapp/src/views/projects/project/components/BaseLanguageSelect.tsx (1)
24-24
: Consider simplifying the default value assignment.The logical OR operation might be unnecessary if
minHeight
is explicitly passed asfalse
. Consider using nullish coalescing or a more explicit default value pattern.- const minHeight = props.minHeight || false; + const minHeight = props.minHeight ?? false;webapp/src/ee/glossary/components/GlossaryViewListRow.tsx (2)
45-47
: Consider extracting permission logic to a custom hook.The permission check logic could be extracted into a reusable hook like
useCanEditGlossary()
for better maintainability and testing.// In a separate hooks file export const useCanEditGlossary = () => { const { preferredOrganization } = usePreferredOrganization(); return ['OWNER', 'MAINTAINER'].includes( preferredOrganization?.currentUserRole || '' ); };
88-106
: Consider extracting magic numbers to named constants.The height calculation function uses magic numbers that could be extracted to named constants for better maintainability.
+const HEIGHT_CONSTANTS = { + BASE: 58, + DEFAULT_FALLBACK: 84, + TAGS: 25, + DESCRIPTION: 26, +} as const; export const estimateGlossaryViewListRowHeight = ( row?: SimpleGlossaryTermWithTranslationsModel ): number => { if (!row) { - return 84; + return HEIGHT_CONSTANTS.DEFAULT_FALLBACK; } - const base = 58; + const base = HEIGHT_CONSTANTS.BASE; const tags = row.flagNonTranslatable || row.flagAbbreviation || row.flagCaseSensitive || row.flagForbiddenTerm - ? 25 + ? HEIGHT_CONSTANTS.TAGS : 0; - const description = row.description ? 26 : 0; + const description = row.description ? HEIGHT_CONSTANTS.DESCRIPTION : 0; return base + tags + description; };webapp/src/component/layout/HeaderBar.tsx (1)
37-37
: Replace deprecated React.VFC with React.FC
React.VFC
has been deprecated. UseReact.FC
instead for better future compatibility.-export const HeaderBar: React.VFC<HeaderBarProps> = (props) => { +export const HeaderBar: React.FC<HeaderBarProps> = (props) => {webapp/src/ee/glossary/components/GlossaryListTranslationCell.tsx (1)
66-66
: Replace deprecated React.VFC with React.FC
React.VFC
has been deprecated. UseReact.FC
instead.-export const GlossaryListTranslationCell: React.VFC<Props> = ({ +export const GlossaryListTranslationCell: React.FC<Props> = ({webapp/src/ee/glossary/components/GlossaryBatchToolbar.tsx (2)
48-48
: Replace deprecated React.VFC with React.FC
React.VFC
has been deprecated. UseReact.FC
instead.-export const GlossaryBatchToolbar: React.VFC<Props> = ({ +export const GlossaryBatchToolbar: React.FC<Props> = ({
116-118
: Consider making the Select component functionalThe Select component appears to be decorative only with a single "Delete terms" option. Consider either making it functional with multiple batch operations or simplifying the UI if only one action is available.
If only delete operation is needed:
- <Select variant="outlined" size="small" value={0} sx={{ minWidth: 250 }}> - <MenuItem value={0}>Delete terms</MenuItem> - </Select> + <Typography variant="body2">Delete selected terms</Typography>e2e/cypress/compounds/glossaries/E2GlossaryView.ts (1)
79-79
: Remove trailing empty line.-} - +}webapp/src/views/projects/translations/translationVisual/TranslationWithPlaceholders.tsx (1)
49-60
: Consider optimizing the overlap detection algorithm.The current implementation has O(n*m) complexity where n is the number of existing modifiers and m is the number of highlights. For large texts with many highlights, this could become a performance bottleneck.
Consider using an interval tree or sorted data structure to improve performance for overlap detection if this becomes a bottleneck with large texts.
webapp/src/ee/glossary/components/GlossaryViewListHeader.tsx (2)
45-48
: Extract grid template calculation to improve readability.The inline grid template calculation makes the component harder to read. Consider extracting it to a helper function.
+const calculateGridTemplate = (languageCount: number) => { + const additionalColumns = Math.max(0, languageCount - 1); + return 'minmax(300px, 1fr)' + ' minmax(200px, 1fr)'.repeat(additionalColumns); +}; export const GlossaryViewListHeader: React.FC<Props> = ({ selectedLanguages, selectionService, }) => { return ( <StyledHeaderRow style={{ - gridTemplateColumns: - 'minmax(300px, 1fr)' + - ' minmax(200px, 1fr)'.repeat((selectedLanguages?.length || 1) - 1), + gridTemplateColumns: calculateGridTemplate(selectedLanguages?.length || 1), }} >
62-62
: Add a comment explaining why the first language is skipped.The code slices from index 1, suggesting the first language has special treatment, but this isn't documented.
</StyledHeaderCell> + {/* Skip the first language as it's displayed in the first column with terms */} {selectedLanguages?.slice(1)?.map((tag, i) => {
webapp/src/constants/links.tsx (2)
301-312
: Alias creates dead-weight – it’s never different fromORGANIZATION_GLOSSARY
ORGANIZATION_GLOSSARY_VIEW
is just a reference toORGANIZATION_GLOSSARY
and does not add any semantic difference or extra behaviour.
Unless you anticipate diverging paths in the near future, the alias only bloats the public surface and forces future refactors to keep two names in sync.- static ORGANIZATION_GLOSSARY_VIEW = LINKS.ORGANIZATION_GLOSSARY;
438-448
: PreferURLSearchParams
for query constructionManually concatenating
?search=${encodedSearch}
works, but usingURLSearchParams
is safer (handles additional parameters, encodings,&
joining, etc.) and self-documenting.-export const getGlossaryTermSearchUrl = ( - organizationSlug: string, - glossaryId: number, - search: string -) => { - const encodedSearch = encodeURIComponent(search.toString()); - return `${LINKS.ORGANIZATION_GLOSSARY.build({ - [PARAMS.ORGANIZATION_SLUG]: organizationSlug, - [PARAMS.GLOSSARY_ID]: glossaryId, - })}?search=${encodedSearch}`; -}; +export const getGlossaryTermSearchUrl = ( + organizationSlug: string, + glossaryId: number, + search: string +) => { + const params = new URLSearchParams({ search }); + return `${LINKS.ORGANIZATION_GLOSSARY.build({ + [PARAMS.ORGANIZATION_SLUG]: organizationSlug, + [PARAMS.GLOSSARY_ID]: glossaryId, + })}?${params.toString()}`; +};webapp/src/ee/glossary/components/GlossaryTermsList.tsx (1)
160-166
: Dependency array won’t react to language content changes
deps={[selectedLanguages]}
passes the array reference toScrollArrows
.
If the caller mutates the array in-place (push/pop), the reference stays the same and the effect insideScrollArrows
won’t run.Unless you always create a fresh array, pass a stable key instead:
- deps={[selectedLanguages]} + deps={[selectedLanguages?.join(',')]}webapp/src/component/layout/BaseView.tsx (1)
94-95
:...props
leaks non-header values intoHeaderBar
BaseViewProps
spreads the full prop bag toHeaderBar
, including layout-only fields (allCentered
,navigation
, etc.).
Although TypeScript’s structural typing allows the call, the extra fields are unused and can trigger needless re-renders when they change.Create a dedicated object with only
HeaderBarProps
to avoid prop-bloat:- <HeaderBar noBorder={Boolean(displayNavigation)} {...props} /> + <HeaderBar + noBorder={Boolean(displayNavigation)} + {...((props as unknown) as HeaderBarProps)} + />(or explicitly pick the relevant fields).
webapp/src/component/searchSelect/InfiniteMultiSearchSelect.tsx (2)
18-21
: Consider using a more specific type instead ofany
.The
_embedded
property usesany
type, which reduces type safety. Consider defining a more specific interface or using a generic type parameter.-type PagedResult = { - _embedded?: any; - page?: components['schemas']['PageMetadata']; -}; +type PagedResult<T = unknown> = { + _embedded?: T; + page?: components['schemas']['PageMetadata']; +};
92-92
: Use optional chaining for better null safety.Apply the static analysis suggestion to use optional chaining instead of logical AND operator.
-onSearchChange && onSearchChange(''); +onSearchChange?.('');🧰 Tools
🪛 Biome (1.9.4)
[error] 92-92: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
webapp/src/service/apiSchema.generated.ts (1)
82-104
: Avoid hand-editing generated files
apiSchema.generated.ts
appears to be produced by an OpenAPI generator. Committing hand changes will be overwritten on the next generation run and will pollute diffs.
Consider:
- Add the file to
.gitignore
, or- Commit it only from CI after generation, or
- Keep it, but document the exact generation command so reviewers can diff the real source (the
yaml/json
spec) instead of the artefact.Leaving it as-is makes reviews noisy and increases merge-conflict risk.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
webapp/src/svgs/icons/glossary-empty.svg
is excluded by!**/*.svg
📒 Files selected for processing (108)
e2e/cypress/common/apiCalls/testData/generator.ts
(1 hunks)e2e/cypress/common/apiCalls/testData/testData.ts
(2 hunks)e2e/cypress/common/constants.ts
(1 hunks)e2e/cypress/compounds/glossaries/E2GlossariesView.ts
(1 hunks)e2e/cypress/compounds/glossaries/E2GlossaryCreateEditDialog.ts
(1 hunks)e2e/cypress/compounds/glossaries/E2GlossaryTermCreateEditDialog.ts
(1 hunks)e2e/cypress/compounds/glossaries/E2GlossaryView.ts
(1 hunks)e2e/cypress/e2e/glossary/create.cy.ts
(1 hunks)e2e/cypress/e2e/glossary/createTerm.cy.ts
(1 hunks)e2e/cypress/e2e/glossary/delete.cy.ts
(1 hunks)e2e/cypress/e2e/glossary/deleteTerm.cy.ts
(1 hunks)e2e/cypress/e2e/glossary/edit.cy.ts
(1 hunks)e2e/cypress/e2e/glossary/editTerm.cy.ts
(1 hunks)e2e/cypress/e2e/glossary/editTranslation.cy.ts
(1 hunks)e2e/cypress/e2e/glossary/highlighting.cy.ts
(1 hunks)e2e/cypress/e2e/glossary/navigation.cy.ts
(1 hunks)e2e/cypress/e2e/glossary/panel.cy.ts
(1 hunks)e2e/cypress/e2e/projects/projectsListDashboard.cy.ts
(1 hunks)e2e/cypress/support/dataCyType.d.ts
(4 hunks)e2e/cypress/support/e2e.ts
(1 hunks)webapp/src/component/common/TooltipCard.tsx
(1 hunks)webapp/src/component/common/form/fields/SearchField.tsx
(1 hunks)webapp/src/component/common/list/SimpleList.tsx
(1 hunks)webapp/src/component/languages/CircledLanguageIconList.tsx
(4 hunks)webapp/src/component/layout/BaseSettingsView/BaseSettingsView.tsx
(2 hunks)webapp/src/component/layout/BaseView.tsx
(3 hunks)webapp/src/component/layout/BaseViewWidth.ts
(1 hunks)webapp/src/component/layout/HeaderBar.tsx
(1 hunks)webapp/src/component/layout/SecondaryBar.tsx
(1 hunks)webapp/src/component/searchSelect/InfiniteMultiSearchSelect.tsx
(1 hunks)webapp/src/component/searchSelect/InfiniteSearchSelect.tsx
(1 hunks)webapp/src/component/searchSelect/InfiniteSearchSelectContent.tsx
(4 hunks)webapp/src/component/searchSelect/MultiselectItem.tsx
(1 hunks)webapp/src/component/searchSelect/SelectItem.tsx
(1 hunks)webapp/src/constants/GlobalValidationSchema.tsx
(1 hunks)webapp/src/constants/links.tsx
(4 hunks)webapp/src/custom.d.ts
(1 hunks)webapp/src/ee/glossary/components/AddFirstGlossaryMessage.tsx
(1 hunks)webapp/src/ee/glossary/components/AssignedProjectsSelect.tsx
(1 hunks)webapp/src/ee/glossary/components/GlossariesEmptyListMessage.tsx
(1 hunks)webapp/src/ee/glossary/components/GlossariesPanel.tsx
(1 hunks)webapp/src/ee/glossary/components/GlossaryBaseLanguageSelect.tsx
(1 hunks)webapp/src/ee/glossary/components/GlossaryBatchToolbar.tsx
(1 hunks)webapp/src/ee/glossary/components/GlossaryCreateEditFields.tsx
(1 hunks)webapp/src/ee/glossary/components/GlossaryCreateEditForm.tsx
(1 hunks)webapp/src/ee/glossary/components/GlossaryEmptyListMessage.tsx
(1 hunks)webapp/src/ee/glossary/components/GlossaryListItem.tsx
(1 hunks)webapp/src/ee/glossary/components/GlossaryListItemMenu.tsx
(1 hunks)webapp/src/ee/glossary/components/GlossaryListStyledRowCell.tsx
(1 hunks)webapp/src/ee/glossary/components/GlossaryListTermCell.tsx
(1 hunks)webapp/src/ee/glossary/components/GlossaryListTranslationCell.tsx
(1 hunks)webapp/src/ee/glossary/components/GlossaryTermCreateEditFields.tsx
(1 hunks)webapp/src/ee/glossary/components/GlossaryTermCreateEditForm.tsx
(1 hunks)webapp/src/ee/glossary/components/GlossaryTermPreview.tsx
(1 hunks)webapp/src/ee/glossary/components/GlossaryTermTags.tsx
(1 hunks)webapp/src/ee/glossary/components/GlossaryTermsList.tsx
(1 hunks)webapp/src/ee/glossary/components/GlossaryViewBody.tsx
(1 hunks)webapp/src/ee/glossary/components/GlossaryViewLanguageSelect.tsx
(1 hunks)webapp/src/ee/glossary/components/GlossaryViewListHeader.tsx
(1 hunks)webapp/src/ee/glossary/components/GlossaryViewListRow.tsx
(1 hunks)webapp/src/ee/glossary/components/GlossaryViewToolbar.tsx
(1 hunks)webapp/src/ee/glossary/components/GlossaryViewTopbar.tsx
(1 hunks)webapp/src/ee/glossary/components/ProjectSelect.tsx
(1 hunks)webapp/src/ee/glossary/components/ScrollArrows.tsx
(1 hunks)webapp/src/ee/glossary/hooks/GlossaryContext.tsx
(1 hunks)webapp/src/ee/glossary/hooks/GlossaryProvider.tsx
(1 hunks)webapp/src/ee/glossary/hooks/useGlossary.ts
(1 hunks)webapp/src/ee/glossary/hooks/useGlossaryContext.ts
(1 hunks)webapp/src/ee/glossary/hooks/useGlossaryTermHighlights.ts
(1 hunks)webapp/src/ee/glossary/hooks/useGlossaryTerms.ts
(1 hunks)webapp/src/ee/glossary/hooks/useSelectedGlossaryLanguages.ts
(1 hunks)webapp/src/ee/glossary/views/GlossariesListView.tsx
(1 hunks)webapp/src/ee/glossary/views/GlossaryCreateDialog.tsx
(1 hunks)webapp/src/ee/glossary/views/GlossaryEditDialog.tsx
(1 hunks)webapp/src/ee/glossary/views/GlossaryRouter.tsx
(1 hunks)webapp/src/ee/glossary/views/GlossaryTermCreateDialog.tsx
(1 hunks)webapp/src/ee/glossary/views/GlossaryTermEditDialog.tsx
(1 hunks)webapp/src/ee/glossary/views/GlossaryView.tsx
(1 hunks)webapp/src/eeSetup/EeModuleType.ts
(1 hunks)webapp/src/eeSetup/eeModule.ee.tsx
(5 hunks)webapp/src/eeSetup/eeModule.oss.tsx
(3 hunks)webapp/src/index.tsx
(2 hunks)webapp/src/service/apiSchema.generated.ts
(42 hunks)webapp/src/service/useSelectionService.ts
(1 hunks)webapp/src/translationTools/useFeatures.tsx
(1 hunks)webapp/src/views/organizations/components/BaseOrganizationSettingsView.tsx
(3 hunks)webapp/src/views/projects/DashboardProjectListItem.tsx
(2 hunks)webapp/src/views/projects/ProjectPage.tsx
(1 hunks)webapp/src/views/projects/project/components/BaseLanguageSelect.tsx
(3 hunks)webapp/src/views/projects/projectMenu/ProjectMenu.tsx
(3 hunks)webapp/src/views/projects/translations/Screenshots/Screenshots.tsx
(1 hunks)webapp/src/views/projects/translations/ToolsPanel/ToolsPanel.tsx
(2 hunks)webapp/src/views/projects/translations/ToolsPanel/common/types.ts
(1 hunks)webapp/src/views/projects/translations/ToolsPanel/panelsList.tsx
(2 hunks)webapp/src/views/projects/translations/TranslationFilters/SubfilterNamespaces.tsx
(2 hunks)webapp/src/views/projects/translations/TranslationFilters/SubfilterTags.tsx
(1 hunks)webapp/src/views/projects/translations/TranslationsList/TranslationRead.tsx
(2 hunks)webapp/src/views/projects/translations/TranslationsList/TranslationWrite.tsx
(1 hunks)webapp/src/views/projects/translations/TranslationsTable/CellLanguage.tsx
(3 hunks)webapp/src/views/projects/translations/TranslationsTable/TranslationRead.tsx
(2 hunks)webapp/src/views/projects/translations/TranslationsTable/TranslationWrite.tsx
(1 hunks)webapp/src/views/projects/translations/TranslationsTable/TranslationsTable.tsx
(3 hunks)webapp/src/views/projects/translations/context/TranslationsContext.ts
(1 hunks)webapp/src/views/projects/translations/context/services/useEditService.tsx
(1 hunks)webapp/src/views/projects/translations/translationVisual/GlossaryHighlight.tsx
(1 hunks)webapp/src/views/projects/translations/translationVisual/TranslationVisual.tsx
(2 hunks)webapp/src/views/projects/translations/translationVisual/TranslationWithPlaceholders.tsx
(4 hunks)webapp/src/views/projects/translations/useTranslationCell.ts
(2 hunks)
✅ Files skipped from review due to trivial changes (15)
- webapp/src/views/projects/translations/Screenshots/Screenshots.tsx
- webapp/src/views/projects/translations/TranslationsList/TranslationWrite.tsx
- e2e/cypress/common/constants.ts
- webapp/src/index.tsx
- e2e/cypress/support/e2e.ts
- webapp/src/ee/glossary/hooks/useGlossary.ts
- webapp/src/ee/glossary/hooks/useGlossaryContext.ts
- webapp/src/component/common/list/SimpleList.tsx
- webapp/src/translationTools/useFeatures.tsx
- webapp/src/component/common/TooltipCard.tsx
- webapp/src/ee/glossary/components/GlossariesEmptyListMessage.tsx
- webapp/src/ee/glossary/components/GlossaryListStyledRowCell.tsx
- webapp/src/ee/glossary/hooks/GlossaryProvider.tsx
- webapp/src/ee/glossary/components/GlossaryViewToolbar.tsx
- webapp/src/eeSetup/EeModuleType.ts
🧰 Additional context used
🧬 Code Graph Analysis (32)
webapp/src/views/projects/translations/ToolsPanel/ToolsPanel.tsx (1)
webapp/src/views/projects/translations/context/TranslationsContext.ts (1)
appendEditValueString
(212-215)
webapp/src/views/projects/translations/ToolsPanel/panelsList.tsx (2)
webapp/src/eeSetup/eeModule.ee.tsx (2)
glossaryPanelAdder
(271-283)translationPanelAdder
(254-269)webapp/src/eeSetup/eeModule.oss.tsx (2)
glossaryPanelAdder
(54-54)translationPanelAdder
(53-53)
webapp/src/ee/glossary/views/GlossaryRouter.tsx (3)
webapp/src/ee/glossary/hooks/GlossaryContext.tsx (1)
GlossaryContext
(14-79)webapp/src/constants/links.tsx (1)
LINKS
(68-421)webapp/src/ee/glossary/views/GlossaryView.tsx (1)
GlossaryView
(11-66)
webapp/src/views/organizations/components/BaseOrganizationSettingsView.tsx (1)
webapp/src/constants/links.tsx (1)
LINKS
(68-421)
webapp/src/ee/glossary/hooks/useSelectedGlossaryLanguages.ts (1)
webapp/src/ee/glossary/hooks/useGlossary.ts (1)
useGlossary
(3-3)
webapp/src/views/projects/projectMenu/ProjectMenu.tsx (1)
webapp/src/constants/links.tsx (1)
LINKS
(68-421)
e2e/cypress/e2e/glossary/editTerm.cy.ts (4)
e2e/cypress/compounds/glossaries/E2GlossaryView.ts (1)
E2GlossaryView
(10-78)e2e/cypress/compounds/glossaries/E2GlossaryTermCreateEditDialog.ts (1)
E2GlossaryTermCreateEditDialog
(3-63)e2e/cypress/common/apiCalls/testData/testData.ts (1)
glossaryTestData
(124-124)e2e/cypress/common/shared.ts (1)
gcy
(28-29)
webapp/src/component/searchSelect/SelectItem.tsx (2)
webapp/src/component/ListComponents.tsx (1)
CompactMenuItem
(17-20)webapp/src/component/searchSelect/MultiselectItem.tsx (1)
MultiselectItem
(36-56)
e2e/cypress/e2e/glossary/editTranslation.cy.ts (4)
e2e/cypress/common/apiCalls/testData/generator.ts (1)
TestDataStandardResponse
(24-34)e2e/cypress/common/apiCalls/testData/testData.ts (1)
glossaryTestData
(124-124)e2e/cypress/compounds/glossaries/E2GlossaryView.ts (1)
E2GlossaryView
(10-78)e2e/cypress/common/shared.ts (1)
gcy
(28-29)
webapp/src/views/projects/translations/TranslationsTable/TranslationsTable.tsx (1)
webapp/src/views/projects/translations/useColumns.ts (1)
startResize
(45-47)
e2e/cypress/compounds/glossaries/E2GlossaryCreateEditDialog.ts (1)
e2e/cypress/common/shared.ts (1)
gcy
(28-29)
e2e/cypress/e2e/glossary/createTerm.cy.ts (4)
e2e/cypress/common/apiCalls/testData/generator.ts (1)
TestDataStandardResponse
(24-34)e2e/cypress/common/apiCalls/testData/testData.ts (1)
glossaryTestData
(124-124)e2e/cypress/compounds/glossaries/E2GlossaryView.ts (1)
E2GlossaryView
(10-78)e2e/cypress/common/shared.ts (1)
gcy
(28-29)
webapp/src/component/searchSelect/MultiselectItem.tsx (1)
webapp/src/component/ListComponents.tsx (1)
CompactMenuItem
(17-20)
webapp/src/ee/glossary/components/GlossaryEmptyListMessage.tsx (2)
webapp/src/component/common/EmptyState.tsx (1)
EmptyState
(24-42)webapp/src/constants/links.tsx (1)
Link
(1-45)
e2e/cypress/e2e/glossary/highlighting.cy.ts (2)
e2e/cypress/common/apiCalls/testData/testData.ts (2)
glossaryTestData
(124-124)getProjectByNameFromTestData
(193-198)e2e/cypress/common/shared.ts (1)
gcy
(28-29)
e2e/cypress/e2e/glossary/navigation.cy.ts (5)
e2e/cypress/common/apiCalls/testData/generator.ts (1)
TestDataStandardResponse
(24-34)e2e/cypress/common/apiCalls/testData/testData.ts (2)
glossaryTestData
(124-124)getOrganizationByNameFromTestData
(170-175)e2e/cypress/common/constants.ts (1)
HOST
(1-1)e2e/cypress/common/shared.ts (1)
gcy
(28-29)e2e/cypress/compounds/glossaries/E2GlossariesView.ts (1)
E2GlossariesView
(8-53)
webapp/src/views/projects/translations/TranslationsTable/CellLanguage.tsx (1)
webapp/src/service/apiSchema.generated.ts (1)
components
(969-5405)
webapp/src/ee/glossary/views/GlossaryTermCreateDialog.tsx (4)
webapp/src/ee/glossary/components/GlossaryTermCreateEditForm.tsx (2)
CreateOrUpdateGlossaryTermRequest
(16-18)GlossaryTermCreateEditForm
(50-102)webapp/src/globalContext/helpers.tsx (1)
usePreferredOrganization
(31-43)webapp/src/ee/glossary/hooks/useGlossary.ts (1)
useGlossary
(3-3)webapp/src/service/http/useQueryApi.ts (1)
useApiMutation
(224-265)
webapp/src/ee/glossary/hooks/useGlossaryTermHighlights.ts (5)
webapp/src/eeSetup/EeModuleType.ts (2)
GlossaryTermHighlightModel
(40-41)GlossaryTermHighlightsProps
(45-49)webapp/src/eeSetup/eeModule.ee.tsx (1)
useGlossaryTermHighlights
(414-416)webapp/src/eeSetup/eeModule.oss.tsx (1)
useGlossaryTermHighlights
(65-67)webapp/src/globalContext/helpers.tsx (1)
useEnabledFeatures
(49-61)webapp/src/service/http/useQueryApi.ts (1)
useApiQuery
(119-141)
e2e/cypress/compounds/glossaries/E2GlossariesView.ts (5)
e2e/cypress/common/apiCalls/testData/generator.ts (1)
TestDataStandardResponse
(24-34)e2e/cypress/common/apiCalls/testData/testData.ts (1)
getOrganizationByNameFromTestData
(170-175)e2e/cypress/common/constants.ts (1)
HOST
(1-1)e2e/cypress/common/shared.ts (2)
gcy
(28-29)confirmHardMode
(63-72)e2e/cypress/compounds/glossaries/E2GlossaryCreateEditDialog.ts (1)
E2GlossaryCreateEditDialog
(3-42)
webapp/src/ee/glossary/components/GlossaryCreateEditFields.tsx (3)
webapp/src/component/common/form/fields/TextField.tsx (1)
TextField
(12-34)webapp/src/ee/glossary/components/AssignedProjectsSelect.tsx (1)
AssignedProjectsSelect
(23-131)webapp/src/ee/glossary/components/GlossaryBaseLanguageSelect.tsx (1)
GlossaryBaseLanguageSelect
(27-140)
e2e/cypress/compounds/glossaries/E2GlossaryTermCreateEditDialog.ts (1)
e2e/cypress/common/shared.ts (1)
gcy
(28-29)
e2e/cypress/compounds/glossaries/E2GlossaryView.ts (5)
e2e/cypress/common/apiCalls/testData/generator.ts (1)
TestDataStandardResponse
(24-34)e2e/cypress/common/apiCalls/testData/testData.ts (2)
getOrganizationByNameFromTestData
(170-175)getGlossaryByNameFromOrganizationData
(177-182)e2e/cypress/common/constants.ts (1)
HOST
(1-1)e2e/cypress/common/shared.ts (2)
gcy
(28-29)confirmStandard
(74-76)e2e/cypress/compounds/glossaries/E2GlossaryTermCreateEditDialog.ts (1)
E2GlossaryTermCreateEditDialog
(3-63)
e2e/cypress/e2e/glossary/edit.cy.ts (4)
e2e/cypress/compounds/glossaries/E2GlossariesView.ts (1)
E2GlossariesView
(8-53)e2e/cypress/compounds/glossaries/E2GlossaryCreateEditDialog.ts (1)
E2GlossaryCreateEditDialog
(3-42)e2e/cypress/common/apiCalls/testData/testData.ts (1)
glossaryTestData
(124-124)e2e/cypress/common/shared.ts (1)
gcy
(28-29)
webapp/src/eeSetup/eeModule.oss.tsx (4)
webapp/src/eeSetup/eeModule.ee.tsx (3)
glossaryPanelAdder
(271-283)useGlossaryTermHighlights
(414-416)GlossaryTermPreview
(418-419)webapp/src/ee/glossary/hooks/useGlossaryTermHighlights.ts (1)
useGlossaryTermHighlights
(10-43)webapp/src/eeSetup/EeModuleType.ts (3)
GlossaryTermHighlightsProps
(45-49)GlossaryTermHighlightModel
(40-41)GlossaryTermPreviewProps
(51-58)webapp/src/ee/glossary/components/GlossaryTermPreview.tsx (1)
GlossaryTermPreview
(85-209)
webapp/src/ee/glossary/components/GlossaryViewLanguageSelect.tsx (6)
webapp/src/service/apiSchema.generated.ts (1)
components
(969-5405)webapp/src/globalContext/helpers.tsx (1)
usePreferredOrganization
(31-43)webapp/src/ee/glossary/hooks/useGlossary.ts (1)
useGlossary
(3-3)webapp/src/service/http/useQueryApi.ts (2)
useApiQuery
(119-141)useApiInfiniteQuery
(95-117)webapp/src/component/searchSelect/MultiselectItem.tsx (1)
MultiselectItem
(36-56)webapp/src/component/searchSelect/InfiniteMultiSearchSelect.tsx (1)
InfiniteMultiSearchSelect
(47-186)
webapp/src/views/projects/project/components/BaseLanguageSelect.tsx (2)
webapp/src/service/apiSchema.generated.ts (1)
components
(969-5405)backend/data/src/main/kotlin/io/tolgee/repository/LanguageRepository.kt (2)
value
(87-129)value
(131-159)
e2e/cypress/common/apiCalls/testData/testData.ts (1)
e2e/cypress/common/apiCalls/testData/generator.ts (2)
generateTestDataObject
(36-41)TestDataStandardResponse
(24-34)
webapp/src/component/layout/HeaderBar.tsx (2)
webapp/src/component/layout/BaseViewWidth.ts (2)
BaseViewWidth
(8-8)getBaseViewWidth
(10-12)webapp/src/component/layout/SecondaryBar.tsx (1)
SecondaryBar
(13-29)
webapp/src/ee/glossary/components/GlossaryViewTopbar.tsx (1)
webapp/src/ee/glossary/components/GlossaryViewLanguageSelect.tsx (1)
GlossaryViewLanguageSelect
(30-221)
webapp/src/ee/glossary/components/AddFirstGlossaryMessage.tsx (1)
webapp/src/constants/links.tsx (1)
Link
(1-45)
webapp/src/component/layout/BaseView.tsx (2)
webapp/src/component/layout/BaseViewWidth.ts (1)
BaseViewWidth
(8-8)webapp/src/component/layout/HeaderBar.tsx (2)
HeaderBarProps
(19-35)HeaderBar
(37-99)
🪛 Biome (1.9.4)
webapp/src/component/searchSelect/InfiniteSearchSelect.tsx
[error] 93-93: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
webapp/src/component/searchSelect/InfiniteMultiSearchSelect.tsx
[error] 92-92: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
🔇 Additional comments (146)
webapp/src/views/projects/translations/TranslationFilters/SubfilterTags.tsx (1)
152-152
: LGTM! Component API update follows expected patterns.The change from
getOptionLabel
toitemKey
prop aligns with the search select component refactoring described in the summary. Usingitem.id
for key generation ensures proper item identification in the infinite scroll list.webapp/src/views/projects/translations/TranslationsTable/TranslationWrite.tsx (1)
135-135
: LGTM! Glossary highlighting integration is properly implemented.The addition of
showHighlights={language.base}
toTranslationVisual
in read-only mode correctly enables glossary term highlighting for base language translations, which aligns with the glossary feature implementation.webapp/src/views/projects/translations/ToolsPanel/common/types.ts (1)
23-23
: LGTM! Type definition properly extends panel functionality.The addition of
appendValue: (value: string) => void
method toPanelContentProps
follows TypeScript best practices and logically extends the existing interface to support text appending functionality for glossary features.webapp/src/views/projects/ProjectPage.tsx (1)
20-20
:✅ Verification successful
LGTM! Refactoring reduces prop drilling effectively.
Removing the
id={project.id}
prop fromProjectMenu
is a good refactoring that eliminates unnecessary prop drilling, as the component now uses theuseProject
hook internally to access the same data.Let me verify that
ProjectMenu
properly uses theuseProject
hook:
🏁 Script executed:
#!/bin/bash # Description: Verify that ProjectMenu component uses useProject hook internally # Expected: ProjectMenu should import and use useProject hook # Search for useProject usage in ProjectMenu component rg -A 10 -B 5 "useProject" --type tsx "webapp/src/views/projects/projectMenu/ProjectMenu.tsx"Length of output: 119
Re-running search without file-type filtering to locate
useProject
in ProjectMenu:
🏁 Script executed:
#!/bin/bash # Search for any usage of useProject in ProjectMenu component rg -n "useProject" -C 5 webapp/src/views/projects/projectMenu/ProjectMenu.tsxLength of output: 1293
Approve:
ProjectMenu
usesuseProject
internally, soid
prop removal is safe
- In
webapp/src/views/projects/projectMenu/ProjectMenu.tsx
,useProject
is imported (line 25) and invoked (const project = useProject();
on line 28).- Removing
id={project.id}
from<ProjectMenu />
inwebapp/src/views/projects/ProjectPage.tsx
(line 20) is therefore safe and eliminates unnecessary prop drilling.LGTM!
webapp/src/component/layout/SecondaryBar.tsx (1)
19-19
: LGTM! Clean conditional spacing implementation.The conditional spacing logic is well-implemented and maintains backward compatibility while providing the flexibility needed for different layout contexts.
Also applies to: 23-23
e2e/cypress/e2e/projects/projectsListDashboard.cy.ts (1)
69-69
:✅ Verification successful
Verify the updated selector exists in the refactored component.
The selector change aligns with the component refactoring from
ProjectLanguages
toCircledLanguageIconList
. Please ensure the newdata-cy="language-icon-list-item"
attribute exists in the updated component.
🏁 Script executed:
#!/bin/bash # Verify the new data-cy attribute exists in the codebase rg -A 3 -B 3 'language-icon-list-item' --type tsx --type tsLength of output: 87
We need to retry searching without the invalid type filters to confirm the selector exists.
🏁 Script executed:
#!/bin/bash # Retry searching for the new data-cy attribute across all files rg 'data-cy="language-icon-list-item"' -A3 -B3 .Length of output: 1912
Confirmed:
data-cy="language-icon-list-item"
exists in the refactored componentThe updated selector in e2e/cypress/e2e/projects/projectsListDashboard.cy.ts (line 69) is correct—the
language-icon-list-item
attribute is defined multiple times in:
- webapp/src/component/languages/CircledLanguageIconList.tsx
No further changes are needed.
webapp/src/views/projects/translations/ToolsPanel/ToolsPanel.tsx (2)
46-47
: LGTM! Clean integration of the append functionality.The destructuring follows the existing pattern and the action is properly integrated into the translations context.
76-76
: Good API design with clear naming.The mapping from
appendEditValueString
toappendValue
provides a clean, concise API for child components while maintaining descriptive naming at the context level.webapp/src/custom.d.ts (1)
110-112
:✅ Verification successful
Well-implemented utility type, but verify its usage.
The
KeyOf<T>
utility type is correctly implemented using mapped types and conditional filtering. However, ensure this type is actually being used in the codebase to avoid introducing dead code.
🏁 Script executed:
#!/bin/bash # Search for usage of the KeyOf utility type rg -A 2 -B 2 'KeyOf<' --type tsx --type tsLength of output: 72
I’ve updated the search to scan all TS/TSX files without relying on
rg
’s built-in types:
🏁 Script executed:
#!/bin/bash # Search for usage of the KeyOf utility type across TS and TSX files rg 'KeyOf<' -n --glob '*.ts' --glob '*.tsx'Length of output: 305
Utility type KeyOf usage confirmed
A search across
.ts
/.tsx
files showsReact.KeyOf
being used in two components, so this utility isn’t dead code:•
webapp/src/ee/glossary/components/ProjectSelect.tsx:15
•webapp/src/views/projects/project/components/BaseLanguageSelect.tsx:16
No further changes needed—this addition is both correct and utilized.
webapp/src/views/projects/translations/TranslationFilters/SubfilterNamespaces.tsx (2)
97-97
: Good practice: Prevent redundant fetch requests.The addition of
!dataLoadable.isFetching
correctly prevents multiple simultaneous fetch requests, which helps avoid race conditions and reduces unnecessary API load.
153-153
: Improved rendering performance with itemKey prop.Adding the
itemKey
prop with a unique identifier function enhances React's ability to track list items efficiently, improving rendering performance for the infinite search select.webapp/src/views/projects/translations/useTranslationCell.ts (2)
208-208
: Good addition for glossary feature integration.The new
editingLanguageTag
property provides necessary context for glossary term highlighting functionality, enhancing the translation editing experience.
59-59
:✅ Verification successful
Verify the cursor selection logic change.
The removal of the language tag check broadens the cursor selection scope. Previously, the cursor was only returned for matching language tags. Ensure this change aligns with the intended behavior for the glossary feature and doesn't cause unintended side effects.
🏁 Script executed:
#!/bin/bash # Description: Check how cursor is used in translation components to verify the impact of removing language tag check # Search for cursor usage patterns in translation components rg -A 3 -B 3 "cursor\?" --type tsx webapp/src/views/projects/translations/ # Look for specific cursor language checks that might be affected rg "cursor.*language" --type tsx webapp/src/views/projects/translations/Length of output: 207
Let’s search without restricting the file type to uncover all uses of
cursor
and anylanguageTag
references in the translations folder:
🏁 Script executed:
#!/bin/bash # Search for cursor usage across .ts and .tsx files in the translations directory rg -n "cursor" -g "*.ts*" webapp/src/views/projects/translations/ -C 3 # Specifically look for any cursor.languageTag references rg -n "cursor.*languageTag" webapp/src/views/projects/translations/ -C 3Length of output: 29195
No action needed – cursor selection update is intentional and safe
The selector now returns any cursor matching the keyId, while language-specific logic remains applied in isEditing and related checks. This change ensures row-level selection works correctly (key cell vs. translation cell), and all language filtering still happens downstream.
webapp/src/views/projects/DashboardProjectListItem.tsx (2)
22-22
: Clean component import update.The import change from
ProjectLanguages
toCircledLanguageIconList
aligns with the component refactoring mentioned in the summary.
175-175
: Improved component interface with better separation of concerns.The new
CircledLanguageIconList
component with directlanguages
prop is better than passing the entire project object, following the principle of passing only the data that's actually needed.webapp/src/views/projects/translations/context/TranslationsContext.ts (1)
212-215
: Well-implemented action for glossary term insertion.The new
appendEditValueString
action follows consistent patterns with existing edit actions and properly integrates with the side panel state management. This enhances the glossary feature by enabling term insertion into translations.webapp/src/views/projects/translations/ToolsPanel/panelsList.tsx (2)
15-15
: LGTM! Clean composition pattern.The import of
glossaryPanelAdder
follows the same pattern as the existingtranslationPanelAdder
, maintaining consistency with the modular panel system.
59-59
: Excellent layering approach for panel composition.The function composition
glossaryPanelAdder(translationPanelAdder(BASE_PANELS))
follows a clean pattern that allows both EE features to be added incrementally while gracefully falling back to no-ops in the OSS version. This maintains proper separation of concerns between base panels and enterprise features.webapp/src/views/projects/translations/translationVisual/TranslationVisual.tsx (3)
21-21
: Well-designed optional props for glossary functionality.The new optional props
targetLocale
andshowHighlights
are properly typed and maintain backward compatibility. The naming clearly indicates their purpose for glossary term highlighting.Also applies to: 24-24
32-32
: Correct parameter destructuring.The new props are properly extracted in the component parameters, maintaining consistency with the existing destructuring pattern.
Also applies to: 35-35
65-65
: Proper prop forwarding to child component.The new props are correctly passed to
TranslationWithPlaceholders
, enabling the glossary highlighting functionality at the appropriate level in the component hierarchy.Also applies to: 67-67
webapp/src/views/projects/projectMenu/ProjectMenu.tsx (4)
25-25
: Good addition of useProject hook import.Adding the
useProject
hook import supports the refactoring to remove prop dependency and use internal context management.
27-28
: Excellent refactoring to use internal project context.Removing the
id
prop and usinguseProject()
hook internally reduces prop drilling and makes the component self-contained. This is a good architectural improvement that aligns with React best practices.
118-120
: Correct usage of project data from hook.The
matchAsPrefix
property correctly usesproject.id
from the hook, maintaining consistency with the refactoring approach.
157-160
: Robust link building with proper null safety.The link building logic properly uses both
project.id
andproject.organizationOwner?.slug
with appropriate null safety. The fallback to empty string for the organization slug ensures the links will still work even if the organization data is not available.webapp/src/views/projects/translations/context/services/useEditService.tsx (2)
179-187
: LGTM! Clean implementation following established patterns.The
appendEditValueString
function correctly:
- Guards against missing position
- Uses consistent variant handling with fallback to 'other'
- Leverages the existing
setEditValueString
method- Follows the same code style as other methods in this service
193-193
: Good addition to the public API.Exposing
appendEditValueString
in the returned object allows consumers to append text to translations, which integrates well with the glossary feature.webapp/src/ee/glossary/views/GlossaryRouter.tsx (1)
13-19
: Clean router structure with appropriate context wrapping.The router correctly:
- Wraps routes in
GlossaryContext
to provide glossary-specific data- Uses exact path matching for the glossary view
- Follows established routing patterns in the codebase
webapp/src/views/projects/translations/TranslationsTable/TranslationRead.tsx (2)
56-57
: Good integration of editing state for glossary highlighting.The destructuring of
isEditingRow
andeditingLanguageTag
from tools provides the necessary data for enabling glossary term highlighting functionality.
95-97
: Appropriate conditional logic for glossary highlights.The props passed to
TranslationVisual
correctly:
- Pass
editingLanguageTag
astargetLocale
for highlight context- Enable
showHighlights
only when editing a row AND the language has a base (non-default language)This ensures highlights are shown at the right time and context.
e2e/cypress/common/apiCalls/testData/generator.ts (1)
27-32
: LGTM! Type definition properly extended for glossary feature.The addition of the
glossaries
property to the organization type follows the existing pattern and structure of other entities in the test data response.webapp/src/views/organizations/components/BaseOrganizationSettingsView.tsx (2)
52-53
: Good refactoring to eliminate code duplication.The
canManageOrganization
variable consolidates the repeated permission check logic, improving maintainability.
79-84
:❓ Verification inconclusive
Verify glossary access permissions.
The glossaries menu item is added outside the
canManageOrganization
check, making it accessible to all organization members. Please confirm this is the intended behavior for glossary access.
🌐 Web query:
What are the typical access permissions for glossary features in translation management platforms?
💡 Result:
Glossary features in translation management platforms typically come with a variety of access permissions that help organizations control who can view, create, edit, and manage terminology. These permissions ensure proper terminology governance while allowing for efficient collaboration.
User Roles and Glossary Permissions
Translation management platforms generally offer role-based access control for glossaries, with different permission levels available for different types of users:
Administrator-Level Permissions
Account Owners and Project Managers typically have full access to glossary features, including:
- Adding, editing, and removing glossary terms and associated blocklist terms[1]
- Updating existing glossaries from file imports[1]
- Defining which user roles have permission to modify glossaries[3]
- Managing user roles and access rights to glossaries[8]
Translator-Level Permissions
Linguists and translation resources may have more limited permissions:
- View glossary terms (often a minimum recommended permission level)[1]
- Add new terms (with proper configuration)[5]
- Edit existing terms (if granted permission)[5]
- Access to term definitions and translations[7]
Agency-Level Permissions
For organizations working with external translation agencies:
- Agency Account Owners can be granted specific glossary permissions[1][5]
- Translation Resource Managers can customize permissions for their team members[1]
- Agency users can edit terms in the CAT (Computer-Assisted Translation) Tool if given proper permissions[5]
Configurable Permission Settings
Most modern translation management systems offer granular control over glossary-related permissions:
- Case-sensitive term management: Controlling who can mark terms as case-sensitive[5]
- Exact match settings: Permissions to define terms that require exact matching[5]
- Term variations: Ability to add and manage term variations[5]
- DNT (Do Not Translate) marking: Rights to mark terms that should not be translated[5]
- Import/Export capabilities: Permissions to import or export glossaries in various formats (CSV, TBX, etc.)[7][9]
Implementation in Popular Platforms
Different translation management systems implement glossary permissions in various ways:
- Smartling: Offers highly configurable permissions for Agency Owners and Translation Resource users, with options to add/edit/remove terms directly in the CAT Tool[1][5]
- Transifex: Administrators can define which user roles have permission to modify specific glossaries through a dedicated "Manage Permissions" interface[3]
- WPML: Allows Translation Managers to edit glossary entries without requiring admin rights[6]
- Pairaphrase: Provides user permissions control to assign different access levels for glossary management based on team members' responsibilities[7]
- Gridly: Enables easy glossary setup with permission controls for inviting and assigning access to translators[9]
Benefits of Granular Permissions
Having detailed permission controls for glossaries offers several advantages:
- Consistency: Ensures standardized terminology across all translations[7]
- Quality improvement: Reduces errors and improves overall translation quality[7]
- Security enhancement: Protects sensitive terminology information through proper access control[7]
- Workflow efficiency: Enables proper task delegation while maintaining oversight[7]
By properly configuring glossary permissions, organizations can maintain terminology control while allowing for collaborative glossary management across their translation workflows.
Citations:
- 1: https://help.smartling.com/hc/en-us/articles/1260805573949-Configurable-Permissions-for-Agency-Owners-Translation-Resource-Managers-Translation-Resource-users
- 2: https://cloud.google.com/translate/docs/advanced/glossary
- 3: https://help.transifex.com/en/articles/6229139-glossary-permissions
- 4: https://www.bureauworks.com
- 5: https://help.smartling.com/hc/en-us/articles/115003080574-Add-or-Edit-a-Glossary-Term
- 6: https://wpml.org/forums/topic/allow-a-translator-of-my-choosing-to-be-able-to-edit-glossary-entries/
- 7: https://www.pairaphrase.com/blog/best-translation-collaboration-tools
- 8: https://logoport.lionbridge.com/help/PDFs/Introduction_to_the_Translation_Workspace.pdf
- 9: https://help.gridly.com/tms-setup-guide
- 10: https://theactionsportstranslator.com/blog/guide-translation-management-systems/
Verify glossary menu visibility scope
The
Glossaries
menu item is currently added outside thecanManageOrganization
guard, making it visible to all organization members. In most TMS platforms, viewing glossaries may be open to all users, but creating/editing is restricted to managers. Please confirm the intended behavior:• File: webapp/src/views/organizations/components/BaseOrganizationSettingsView.tsx
Lines: 79–84menuItems.push({ link: LINKS.ORGANIZATION_GLOSSARIES.build({ [PARAMS.ORGANIZATION_SLUG]: organizationSlug, }), label: t('organization_menu_glossaries'), });• If all members should only view glossaries, ensure edit/create controls inside the glossary page are gated by
canManageOrganization
.
• If only managers should access glossaries at all, wrap thismenuItems.push
call in thecanManageOrganization
check.webapp/src/views/projects/translations/TranslationsTable/TranslationsTable.tsx (2)
19-19
: Import path update looks good.Moving
useScrollStatus
to a shared common component location improves code organization.
283-283
: Good fix for column index calculation.The change from
onResize={startResize}
toonResize={() => startResize(i - 1)}
correctly adjusts for the key column being at index 0, ensuring language columns get the proper 0-based index for resizing.e2e/cypress/e2e/glossary/editTerm.cy.ts (3)
11-19
: LGTM! Excellent test setup with proper data isolation.The beforeEach hook properly handles test data generation, login, navigation, and dialog opening. The chained approach with promise handling ensures proper test sequencing.
25-30
: Good test case structure for name editing.The test follows a clear arrange-act-assert pattern and properly verifies that the edited term name appears in the list.
42-59
: Excellent verification pattern for persistent state changes.The test correctly verifies flag changes by reopening the dialog after submission and checking the checkbox states. The cleanup with
dialogAfterEdit.cancel()
is a good practice to avoid affecting subsequent tests.webapp/src/views/projects/translations/translationVisual/GlossaryHighlight.tsx (2)
8-12
: Well-designed highlight styling with theme integration.The dashed underline with proper offset provides clear visual indication of glossary terms while maintaining readability.
27-45
: Excellent tooltip integration with accessibility considerations.The 200ms enter delay prevents tooltip flicker during cursor movement, and the bottom-start placement ensures good visibility. The data-cy attribute supports E2E testing integration.
webapp/src/ee/glossary/components/GlossaryTermTags.tsx (2)
39-47
: Excellent performance optimization with early return.The
hasTags
calculation and early return prevent unnecessary DOM rendering when no flags are set, improving component efficiency.
49-64
: Well-structured conditional rendering with proper translations.The tag rendering logic is clean and follows consistent patterns. Translation keys are appropriately namespaced for the glossary feature.
e2e/cypress/e2e/glossary/delete.cy.ts (3)
10-19
: Proper test data management with isolation.The setup and teardown ensure each test starts with clean, predictable data while maintaining test isolation.
21-29
: Good test coverage for successful deletion workflow.The test properly verifies the complete deletion workflow and confirms the glossary is removed from the UI.
31-38
: Excellent permission testing pattern.This test ensures proper access control by verifying that users without delete permissions cannot see the delete option. This is crucial for security testing.
webapp/src/component/searchSelect/SelectItem.tsx (1)
5-20
: LGTM! Well-structured grid layout with hover effects.The styled component implementation provides a clean three-column grid layout with nice hover transition effects for hidden elements.
webapp/src/views/projects/translations/TranslationsList/TranslationRead.tsx (2)
61-62
: LGTM! Clean integration of glossary editing state.The destructuring of
isEditingRow
andeditingLanguageTag
provides the necessary context for glossary functionality.
123-125
: LGTM! Logical conditional highlighting implementation.The
showHighlights
prop is correctly conditional on both editing state and the presence of a base language, which makes sense for glossary term highlighting functionality.webapp/src/ee/glossary/components/GlossaryTermCreateEditFields.tsx (2)
8-14
: LGTM! Well-organized grid layout for checkbox flags.The grid template areas provide a clean 2x2 layout for the flag checkboxes with semantic naming.
36-95
: LGTM! Comprehensive flag configuration with helpful tooltips.The checkbox configuration covers all necessary glossary term flags with descriptive tooltips and proper accessibility attributes. The consistent tooltip delay and grid area assignments are well implemented.
webapp/src/component/searchSelect/MultiselectItem.tsx (3)
5-21
: LGTM! Consistent grid layout with appropriate styling.The grid layout matches the SelectItem component pattern while accommodating the checkbox. The hover effects and transitions are well implemented.
27-29
: LGTM! Smart checkbox alignment with negative margins.The negative margins on the checkbox provide proper visual alignment within the grid layout without disrupting the overall spacing.
36-56
: LGTM! Proper forwardRef implementation with correct naming.The component correctly uses forwardRef with the matching function name and properly handles all props including the checkbox state.
webapp/src/constants/GlobalValidationSchema.tsx (2)
473-486
: Well-structured glossary creation validation schema.The validation schema correctly enforces business rules with a minimum name length, required base language tag, and optional project assignments. The nested object validation for
baseLanguage
and array validation forassignedProjects
properly align with the backend API expectations.
488-496
: Comprehensive glossary term validation schema.The schema appropriately handles the flexible nature of glossary terms with optional text and nullable description, plus boolean flags for term characteristics. The optional validation approach provides good UX flexibility while maintaining data integrity.
e2e/cypress/e2e/glossary/highlighting.cy.ts (2)
9-21
: Excellent test setup with proper data lifecycle management.The test suite correctly manages test data with clean setup and teardown, ensuring test isolation. The extraction of
projectId
from test data using the helper function maintains good separation of concerns.
23-36
: Comprehensive test coverage for highlighting behavior.The test effectively validates both positive and negative scenarios for glossary term highlighting. The assertions check both existence and content of highlight elements, providing thorough verification of the highlighting feature.
e2e/cypress/e2e/glossary/deleteTerm.cy.ts (3)
7-19
: Proper test data management and setup.The test suite correctly implements data lifecycle management with clean setup and teardown. Storing the complete test data response enables flexible access to test entities throughout the test execution.
21-30
: Effective functional test for term deletion.The test properly validates the complete deletion workflow using the page object pattern. The final assertion confirms the term removal from the UI, ensuring the deletion operation completed successfully.
32-41
: Important permission-based access control validation.This test ensures proper security by verifying that users without appropriate permissions cannot delete terms. The disabled button state validation confirms that the UI correctly enforces permission restrictions.
e2e/cypress/e2e/glossary/createTerm.cy.ts (4)
7-19
: Consistent test data management pattern.The setup follows the established pattern for glossary tests with proper data lifecycle management. The standardized approach ensures reliable test execution across the glossary test suite.
21-36
: Comprehensive term creation test with multiple properties.This test validates a complex term creation scenario with description and multiple flags (case sensitive, abbreviation). The test ensures that all term properties are properly handled during creation and that the term appears in the UI.
38-51
: Important test for non-translatable term functionality.This test specifically validates the non-translatable flag, which is a key feature for glossary terms that should not be translated. The test ensures this specialized term type is properly supported.
53-67
: Good coverage for empty glossary scenario.This test validates the different UI flow when creating the first term in an empty glossary, using the
isFirst
parameter. Testing the forbidden flag in this context ensures comprehensive coverage of term properties and UI states.webapp/src/views/projects/translations/TranslationsTable/CellLanguage.tsx (3)
9-12
: Well-designed type narrowing for better API clarity.The introduction of
CellLanguageModel
that picks only the necessary properties (base
,flagEmoji
,name
) from the fullLanguageModel
is excellent. This clearly documents the component's actual dependencies and prevents unnecessary coupling to the full language model.
23-24
: Simplified and more flexible prop interface.The changes make the component more flexible by:
- Making
onResize
optional instead of required- Removing the
colIndex
parameter from the resize callbackThis simplification suggests the column index is no longer needed by consumers, which is a good refinement.
36-36
: Proper conditional rendering for optional functionality.The conditional rendering of
CellStateBar
only whenonResize
is provided is correct and prevents unnecessary DOM elements when resize functionality isn't needed.e2e/cypress/e2e/glossary/editTranslation.cy.ts (4)
10-19
: Excellent test setup with proper data lifecycle management.The beforeEach/afterEach hooks properly clean and regenerate test data, ensuring test isolation and consistency. This is a solid foundation for reliable e2e tests.
21-28
: Well-structured positive test case for translation editing.The test properly:
- Authenticates as an Owner (who has edit permissions)
- Uses the page object pattern for better maintainability
- Performs the edit operation and verifies the result
30-40
: Good negative test case for non-translatable terms.This test properly verifies that non-translatable terms (like "Apple") cannot be edited by ensuring the edit field doesn't appear when clicked. This is important for data integrity.
51-60
: Important permission boundary test.Testing that Members cannot edit translations is crucial for verifying role-based access controls. The test correctly verifies that the edit field doesn't appear for users without edit permissions.
webapp/src/ee/glossary/views/GlossaryView.tsx (4)
12-14
: Good use of URL state management for search persistence.Using
useUrlSearchState
for the search parameter ensures that search queries persist across page reloads and can be shared via URL, which improves user experience.
26-28
: Appropriate role-based permission checking.The permission check limiting creation to 'OWNER' and 'MAINTAINER' roles is appropriate for glossary management. The fallback to empty string handles the undefined case safely.
52-58
: Well-implemented conditional rendering with proper guards.The conditional rendering checks for:
canCreate
permissioncreateDialogOpen
statepreferredOrganization
existenceThis prevents rendering the dialog when any required condition isn't met, which is good defensive programming.
59-63
: Clean delegation pattern with conditional callback.Passing
onCreate
only whencanCreate
is true and delegating search handling to the child component follows good separation of concerns. The child component can conditionally show/hide the create button based on whether the callback is provided.webapp/src/ee/glossary/components/GlossaryCreateEditForm.tsx (5)
33-43
: Well-structured TypeScript interface for form values.The
CreateEditGlossaryFormValues
type is properly structured with:
- Required name field
- Optional baseLanguage with proper shape
- Array of assigned projects with id references
This provides good type safety for the form data.
62-64
: Appropriate feature flag integration.Checking the GLOSSARY feature flag and using it to disable form inputs and buttons ensures the form respects feature toggles. This is important for gradual feature rollouts.
65-71
: Good loading state handling.Showing a spinner when
initialValues
is undefined prevents rendering an incomplete form and provides clear feedback to users about the loading state.
99-101
: Dynamic button text based on editing mode.The conditional button text (
edit_glossary_submit_button
vscreate_glossary_submit_button
) provides clear context to users about the action they're performing.
88-97
: Good accessibility and testing support.The inclusion of
data-cy
attributes on interactive elements supports automated testing, which is especially important for form components that are frequently tested.webapp/src/component/languages/CircledLanguageIconList.tsx (1)
22-76
: Excellent refactoring for improved reusability.The change from accepting a
project
object to a directlanguages
array makes this component more reusable and follows the single responsibility principle. The updated data-cy attributes maintain test compatibility.webapp/src/ee/glossary/components/AddFirstGlossaryMessage.tsx (1)
1-76
: Well-structured empty state component with proper conditional rendering.The component follows React best practices with proper TypeScript typing, styled components, internationalization support, and conditional button rendering. The hardcoded documentation URL aligns with the PR objectives' expected links.
webapp/src/ee/glossary/views/GlossariesListView.tsx (1)
25-116
: Comprehensive list view with proper feature flag and permission handling.Excellent implementation that properly integrates feature flags, role-based permissions, pagination, search functionality, and handles both enabled/disabled states appropriately. The permission check correctly restricts creation to OWNER/MAINTAINER roles.
webapp/src/ee/glossary/components/GlossaryCreateEditFields.tsx (1)
14-47
: Proper conditional form field rendering with correct prop passing.The conditional logic correctly renders the AssignedProjectsSelect only when needed and properly passes the assignedProjectsName to GlossaryBaseLanguageSelect to enable language filtering by assigned projects. Form integration with Formik through the nested components is handled appropriately.
webapp/src/ee/glossary/components/GlossaryListTermCell.tsx (1)
59-111
: Well-implemented term cell with proper grid layout and event handling.Excellent use of CSS Grid for layout, proper event propagation handling in the checkbox, correct base translation lookup using glossary context, and appropriate text limiting. The edit functionality and selection service integration follow good patterns.
webapp/src/ee/glossary/hooks/GlossaryContext.tsx (1)
65-69
: Error handling looks appropriate.The error handling correctly throws a
GlobalError
with appropriate error codes and messages, providing good user feedback for failure scenarios.webapp/src/ee/glossary/components/GlossaryListItem.tsx (1)
15-31
: Excellent responsive design implementation.The use of CSS container queries for responsive layout is a modern and effective approach. The grid layout adapts well to different screen sizes.
e2e/cypress/compounds/glossaries/E2GlossaryCreateEditDialog.ts (1)
3-42
: Well-structured page object pattern.The class follows good page object model practices with clear method names, consistent patterns, and appropriate verification methods after actions.
webapp/src/ee/glossary/components/GlossaryEmptyListMessage.tsx (1)
82-82
: Documentation links align with PR objectives.The documentation links to
https://docs.tolgee.io/platform/projects_and_organizations/glossary
and the CSV format guide match the expected documentation structure mentioned in the PR objectives.Also applies to: 107-107
webapp/src/ee/glossary/hooks/useGlossaryTerms.ts (1)
58-61
: Add null safety for data access.The optional chaining and nullish coalescing are good, but consider adding explicit error handling for malformed responses.
The data transformation logic correctly handles potential null/undefined values with safe access patterns.
e2e/cypress/e2e/glossary/panel.cy.ts (1)
9-45
: Well-structured E2E test for glossary panel functionality.The test suite follows Cypress best practices with proper setup/teardown, clear assertions, and comprehensive coverage of both positive and negative scenarios. The use of page objects and established test data patterns ensures maintainability.
webapp/src/eeSetup/eeModule.oss.tsx (3)
1-7
: Appropriate addition of glossary-related types.The import additions properly include the necessary TypeScript types for glossary functionality, maintaining type safety in the OSS module.
9-18
: Good refactoring to support forwardRef pattern.Converting
NotIncludedInOss
to useReact.forwardRef
is appropriate for components that may need ref forwarding, ensuring compatibility with the EE module's component interfaces.
54-70
: Well-implemented OSS stubs for glossary functionality.The glossary-related exports appropriately provide:
- No-op function for
glossaryPanelAdder
- Empty array return for
useGlossaryTermHighlights
hook- Placeholder component for
GlossaryTermPreview
This maintains API compatibility while clearly indicating OSS limitations.
e2e/cypress/common/apiCalls/testData/testData.ts (2)
124-124
: Consistent addition of glossary test data.The
glossaryTestData
export follows the established pattern usinggenerateTestDataObject
, maintaining consistency with other test data objects in the file.
177-191
: Well-implemented utility functions for glossary data retrieval.The functions follow established naming conventions and patterns:
- Proper TypeScript typing with
TestDataStandardResponse
structure- Consistent parameter naming and return patterns
- Handles the nested organization/glossary relationship correctly
webapp/src/ee/glossary/components/GlossaryViewBody.tsx (2)
9-13
: Clear and well-typed component interface.The Props type definition is clean and appropriately optional, allowing flexible usage of the component across different contexts.
15-67
: Well-structured component with appropriate separation of concerns.The component effectively orchestrates three child components with proper state management and prop passing. The use of refs for DOM interactions (scrolling and search clearing) is appropriate, and the conditional rendering logic is clear.
Note: The past review comment about file length is no longer applicable - this 67-line component is appropriately sized and well-organized.
webapp/src/component/searchSelect/InfiniteSearchSelect.tsx (1)
46-187
: Well-designed reusable component.The component provides a clean, generic interface for infinite search selection with proper type safety and good separation of concerns. The use of generic types T and S allows for flexibility while maintaining type safety.
🧰 Tools
🪛 Biome (1.9.4)
[error] 93-93: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
webapp/src/component/searchSelect/InfiniteSearchSelectContent.tsx (1)
26-31
: Excellent refactor to improve component flexibility.Removing the generic constraint and introducing the
itemKey
prop makes this component more reusable by not requiring items to have anid
property. The changes are consistent throughout the component.Also applies to: 55-55, 101-101, 105-105
webapp/src/service/useSelectionService.ts (2)
36-178
: Well-designed selection management hook.This hook provides a comprehensive and well-structured API for managing selection state with excellent support for:
- Bulk operations (select/unselect multiple, range, all)
- Asynchronous data fetching for range and all operations
- Loading state management
- Selection validation with helpful warnings
- Clean separation of concerns
The type definitions are clear and the implementation handles edge cases appropriately.
110-118
: Good defensive programming with selection validation.The warning system for detecting when selected count exceeds total count is a nice touch for catching potential bugs during development.
e2e/cypress/compounds/glossaries/E2GlossaryTermCreateEditDialog.ts (1)
54-62
: LGTM: Good assertion patterns for dialog interactions.The cancel and submit methods correctly assert dialog visibility states, ensuring the dialog closes after the action.
e2e/cypress/e2e/glossary/navigation.cy.ts (1)
14-23
: LGTM: Proper test data lifecycle management.Good use of beforeEach/afterEach hooks for test data setup and cleanup, ensuring test isolation.
webapp/src/ee/glossary/components/GlossaryBaseLanguageSelect.tsx (1)
55-81
: LGTM: Well-implemented infinite query with proper pagination.The infinite query implementation correctly handles pagination parameters and next page detection. Good use of
keepPreviousData
and proper page parameter calculation.webapp/src/eeSetup/eeModule.ee.tsx (5)
5-5
: LGTM!Clean addition of the BookClosed icon import for glossary functionality.
50-64
: LGTM!Well-organized imports for glossary types and components. The type imports are properly grouped and the component imports follow a logical structure.
183-188
: LGTM!The glossary routes are properly structured using PrivateRoute for security. The exact path matching and component assignments are correct.
271-283
: LGTM!The glossary panel configuration follows the established pattern and is well-positioned after the translation memory panel. The conditional display logic based on edit permissions is appropriate.
414-419
: LGTM!Clean re-export pattern for glossary functionality. The hook wrapper and component re-export maintain proper abstraction boundaries.
webapp/src/ee/glossary/components/GlossaryTermPreview.tsx (4)
26-50
: LGTM!Well-structured styled components with proper theming integration. The CSS-in-JS approach with conditional classes provides good maintainability.
85-108
: LGTM!Solid component logic for determining which translation to display. The handling of non-translatable terms and language selection is correct.
110-124
: LGTM!Proper event handling implementation. The mouse event management for clickable terms and the prevention of default behavior is well implemented.
126-189
: LGTM!Well-structured conditional rendering with appropriate use of language flags and tooltips. The link generation for opening the full glossary view is properly implemented.
webapp/src/views/projects/project/components/BaseLanguageSelect.tsx (4)
10-10
: LGTM!Good use of type alias to reduce duplication and improve maintainability of the LanguageModel type reference.
13-18
: LGTM!Excellent type safety improvements. The use of
Partial<LanguageModel>[]
for languages andReact.KeyOf<LanguageModel>
for valueKey provides better type checking. The new optional props enhance component flexibility.
47-48
: LGTM!Good addition of the new props to the Select component, providing external control over the component's behavior.
57-57
: LGTM!Improved type safety for the MenuItem value prop using
React.Key
type assertion.e2e/cypress/compounds/glossaries/E2GlossariesView.ts (4)
8-16
: LGTM!Well-structured navigation methods with both direct slug-based navigation and test data lookup. The separation of concerns between finding organization data and visiting the URL is clean.
18-21
: LGTM!Clean method for opening a glossary view with proper return type. The filter and click pattern is appropriate for Cypress testing.
23-34
: LGTM!Good implementation of menu interaction and deletion with proper use of the
confirmHardMode
utility for deletion confirmation. The method composition is clean.
36-52
: LGTM!Excellent dialog opening methods with proper visibility checks and return types. The distinction between first-time creation and regular creation is well handled with the
isFirst
parameter.webapp/src/ee/glossary/views/GlossaryEditDialog.tsx (2)
68-86
: LGTM: Well-structured initial values computation.The
useMemo
hook properly manages the initialization of form values with appropriate dependency array and handles the language metadata mapping correctly.
94-94
: Good practice: Event propagation prevention.The
onClick={(e) => e.stopPropagation()}
on the Dialog prevents unwanted event bubbling, which is a good practice for modal dialogs.webapp/src/ee/glossary/components/GlossaryViewTopbar.tsx (1)
1-68
: LGTM: Well-structured topbar component.The component follows React best practices with clean props interface, proper use of translation hooks, and good component composition. The layout structure is clear and the conditional rendering for the add button is appropriate.
webapp/src/component/layout/BaseSettingsView/BaseSettingsView.tsx (3)
12-14
: Excellent use of modern CSS container queries.The responsive design using container queries (
@container main-container (max-width: 800px)
) is a modern and efficient approach that provides better component isolation compared to traditional media queries.
58-63
: LGTM: Clean delegation to HeaderBar component.The refactor properly delegates header rendering to the new
HeaderBar
component with appropriate props configuration. This improves consistency across the application.
39-40
:✅ Verification successful
Verify breaking change in props interface.
The addition of
allCentered = true
as a default value and the removal of other props (title, addLinkTo, onAdd, addLabel) represents a breaking change. Ensure all existing usages of this component have been updated accordingly.
🏁 Script executed:
#!/bin/bash # Search for usages of BaseSettingsView to verify compatibility with new props interface ast-grep --pattern 'BaseSettingsView $$$'Length of output: 43
🏁 Script executed:
#!/bin/bash # Search for all references to BaseSettingsView to confirm updated props usage rg 'BaseSettingsView' -nLength of output: 1487
🏁 Script executed:
#!/bin/bash # Inspect BaseSettingsView usage in relevant view files to check for removed props files=( "webapp/src/views/userSettings/BaseUserSettingsView.tsx" "webapp/src/views/administration/components/BaseAdministrationView.tsx" "webapp/src/views/organizations/components/BaseOrganizationSettingsView.tsx" ) for file in "${files[@]}"; do echo "=== $file ===" rg '<BaseSettingsView' -n -C 5 "$file" doneLength of output: 2155
#!/bin/bash # Inspect Props interface in BaseSettingsView echo '=== Props interface in BaseSettingsView ===' rg 'interface Props' -n -C 20 webapp/src/component/layout/BaseSettingsView/BaseSettingsView.tsx # Inspect view component definitions echo '=== Signatures of Base*SettingsView components ===' files=( "webapp/src/views/userSettings/BaseUserSettingsView.tsx" "webapp/src/views/administration/components/BaseAdministrationView.tsx" "webapp/src/views/organizations/components/BaseOrganizationSettingsView.tsx" ) for file in "${files[@]}"; do echo "=== $file ===" rg 'export const Base.*View' -n -C 5 "$file" done
🏁 Script executed:
#!/bin/bash # Inspect Props interface in BaseSettingsView echo '=== Props interface in BaseSettingsView ===' rg -n 'interface Props' -C 20 webapp/src/component/layout/BaseSettingsView/BaseSettingsView.tsx echo '' # Search for removed props fields in Props interface echo '=== Removed props in Props interface ===' rg -nE 'title|addLinkTo|onAdd|addLabel' -C 5 webapp/src/component/layout/BaseSettingsView/BaseSettingsView.tsx || echo 'No occurrences of removed props in Props interface' echo '' # Inspect BaseUserSettingsView Props and destructuring echo '=== BaseUserSettingsView Props ===' rg -n 'type Props' -C 10 webapp/src/views/userSettings/BaseUserSettingsView.tsx || echo 'No Props type found' rg -n 'interface Props' -C 10 webapp/src/views/userSettings/BaseUserSettingsView.tsx || echo 'No interface Props found' echo '' # Inspect destructuring and spread in BaseUserSettingsView echo '=== BaseUserSettingsView signature and destructuring ===' rg -n 'export const BaseUserSettingsView' -C 5 webapp/src/views/userSettings/BaseUserSettingsView.tsx rg -n '({[^)]*})' -n -C 3 webapp/src/views/userSettings/BaseUserSettingsView.tsxLength of output: 2380
#!/bin/bash # Extract Props interface from BaseSettingsView echo "=== Props interface in BaseSettingsView ===" awk '/interface Props/,/}/' webapp/src/component/layout/BaseSettingsView/BaseSettingsView.tsx # Inspect BaseAdministrationView definition and destructuring echo "" echo "=== BaseAdministrationView definition ===" rg -n 'export const BaseAdministrationView' -C 10 webapp/src/views/administration/components/BaseAdministrationView.tsx # Inspect BaseOrganizationSettingsView definition and destructuring echo "" echo "=== BaseOrganizationSettingsView definition ===" rg -n 'export const BaseOrganizationSettingsView' -C 10 webapp/src/views/organizations/components/BaseOrganizationSettingsView.tsx
🏁 Script executed:
#!/bin/bash # Verify no usages of removed props on BaseSettingsView echo "Checking for removed props usage:" for prop in title addLinkTo onAdd addLabel; do echo -n " $prop: " rg -n "<BaseSettingsView[^>]*${prop}=" -g '*.tsx' || echo "0 matches" doneLength of output: 717
No breaking changes detected in
BaseSettingsView
props interface.Removed props (
title
,addLinkTo
,onAdd
,addLabel
) are not referenced in any<BaseSettingsView>
usage. The newallCentered
prop defaults totrue
, so existing consumers remain unaffected.e2e/cypress/e2e/glossary/create.cy.ts (1)
8-59
: Well-structured E2E test implementationThe test file follows excellent practices:
- Proper test isolation with setup/teardown
- Clear test scenarios covering different user states
- Good use of page object pattern
- Reusable helper functions for common operations
webapp/src/ee/glossary/components/GlossaryListTranslationCell.tsx (1)
123-132
: Well-implemented keyboard shortcutsGood implementation of keyboard shortcuts with proper handling of Shift+Enter for multiline input and Enter for save action.
webapp/src/ee/glossary/components/GlossaryBatchToolbar.tsx (1)
98-100
: Good role-based access control implementationProper implementation of role-based permissions checking for destructive operations.
e2e/cypress/e2e/glossary/edit.cy.ts (3)
11-20
: LGTM! Proper test setup with data isolation.The beforeEach hook correctly sets up test data, logs in as an owner, and opens the edit dialog for testing. Good practice using
glossaryTestData.clean()
for test isolation.
26-33
: LGTM! Clear and focused test for name editing.The test properly edits the glossary name and verifies the change is reflected in the list view.
35-42
: LGTM! Good persistence verification pattern.The test correctly verifies that the base language change persists by reopening the dialog and checking the value, then properly cancels to avoid side effects.
webapp/src/ee/glossary/views/GlossaryCreateDialog.tsx (2)
88-92
: LGTM! Proper feature flag integration.Good implementation of the disabled feature banner when the glossary feature is not enabled, providing clear feedback to users.
64-77
: LGTM! Comprehensive success handling.Excellent success flow with user feedback, navigation to the new glossary, and callback invocation.
webapp/src/ee/glossary/views/GlossaryTermEditDialog.tsx (3)
89-116
: LGTM! Excellent user protection for destructive changes.The confirmation flow for changing a term to non-translatable is well-implemented. It properly warns users about translation deletion and uses a Promise-based approach to handle the confirmation workflow.
125-130
: LGTM! Robust error handling pattern.All three API queries properly handle errors by closing the dialog, preventing users from interacting with invalid data. This is a good defensive programming practice.
Also applies to: 140-148, 159-168
49-58
: LGTM! Clean data transformation logic.The initialValues computation properly combines term and translation data into the required form structure, with appropriate null checking.
webapp/src/ee/glossary/components/GlossaryListItemMenu.tsx (4)
28-30
: LGTM! Proper role-based access control.The role checking correctly restricts management actions to OWNER and MAINTAINER roles, following the principle of least privilege.
42-57
: LGTM! Excellent delete protection with hard mode.The delete confirmation uses
hardModeText
requiring users to type the glossary name in uppercase, providing strong protection against accidental deletions.
118-130
: LGTM! Proper context provider usage.Good pattern wrapping the edit dialog in a
GlossaryContext
provider to ensure proper data access and state management.
63-65
: LGTM! Proper event handling.Correctly uses
stopPropagation()
to prevent the menu button click from bubbling up to parent elements.webapp/src/component/searchSelect/InfiniteMultiSearchSelect.tsx (1)
95-185
: Well-implemented multi-select component with infinite scrolling.The component structure is excellent with proper:
- Accessibility considerations (tabIndex, ARIA attributes)
- Event handling with stopAndPrevent
- Conditional rendering for search and loading states
- Material-UI integration with custom styling
- Proper ref management for anchor positioning
e2e/cypress/support/dataCyType.d.ts (1)
108-294
: Comprehensive test automation support for glossary functionality.Excellent addition of data-cy attributes that provide thorough test coverage for the new glossary features including:
- Glossary creation/editing dialogs and forms
- Glossary term management with flags and translations
- Glossary list and panel components
- Language selection and project assignment
- Import/export functionality
The naming conventions are consistent and descriptive, making the attributes easy to use in end-to-end tests.
Also applies to: 368-368
webapp/src/service/apiSchema.generated.ts (1)
1680-1693
: OperationId collisions degrade API layer DXSeveral new operations share very generic ids like
create_13
,update_12
,get_22
, etc.
These indices shift every time a new endpoint is added, breaking import paths and creating noisy git history.Assign stable, semantic operationIds in the OpenAPI source, e.g.:
createGlossary updateGlossaryTerm getGlossaryTermTranslation
Most generators (incl.
openapi-typescript
) will then produce predictable names.Also applies to: 1788-1791, 5210-5223
webapp/src/views/projects/translations/translationVisual/TranslationWithPlaceholders.tsx
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review continued from previous batch...
webapp/src/component/searchSelect/InfiniteMultiSearchSelect.tsx
Outdated
Show resolved
Hide resolved
e2c0ab7
to
1eebc2d
Compare
…ropdown close logic
…dle undefined properly
…ojectsSelect + pass props for other components
Implements #2969 and #1418 Requires tolgee/translator#32 to be deployed. Expects these links to be valid documentation links: - https://docs.tolgee.io/platform/projects_and_organizations/glossary -https://docs.tolgee.io/platform/projects_and_organizations/glossary/import/csv-format <!-- This is an auto-generated comment: release notes by coderabbit.ai --> - **New Features** - Introduced a comprehensive Glossary feature for organizations, including management of glossaries, terms, translations, and term highlights. - Added REST API endpoints for creating, updating, deleting, and retrieving glossaries and glossary terms, with support for translations and project assignments. - Implemented listing of languages used by organization projects and glossaries, including base languages. - Added UI components and dialogs for glossary and glossary term management, including batch operations and language selection. - Integrated glossary term highlighting in translation tools to assist translators and reviewers. - Enhanced search and filtering capabilities across glossary terms and languages. - Added extensive end-to-end Cypress tests covering glossary creation, editing, deletion, navigation, highlighting, and permissions. - Introduced feature flag support for the Glossary feature. - **Bug Fixes** - Improved API validation and error handling for glossary-related operations. - **Documentation** - Updated contributor guidelines with enhanced testing and translation key instructions. - **Tests** - Added comprehensive automated tests for glossary APIs, permissions, language endpoints, and UI components ensuring role-based access control and feature robustness. - **Chores** - Refined codebase with annotation updates, suppression of static analysis warnings, and minor refactoring for maintainability. - Updated API schema with glossary-related endpoints and models. - Improved type safety and component abstractions in frontend code. - Added React StrictMode wrapping for the app root. - Enhanced UI components with accessibility and styling improvements. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Implements #2969 and #1418 Requires tolgee/translator#32 to be deployed. Expects these links to be valid documentation links: - https://docs.tolgee.io/platform/projects_and_organizations/glossary -https://docs.tolgee.io/platform/projects_and_organizations/glossary/import/csv-format <!-- This is an auto-generated comment: release notes by coderabbit.ai --> - **New Features** - Introduced a comprehensive Glossary feature for organizations, including management of glossaries, terms, translations, and term highlights. - Added REST API endpoints for creating, updating, deleting, and retrieving glossaries and glossary terms, with support for translations and project assignments. - Implemented listing of languages used by organization projects and glossaries, including base languages. - Added UI components and dialogs for glossary and glossary term management, including batch operations and language selection. - Integrated glossary term highlighting in translation tools to assist translators and reviewers. - Enhanced search and filtering capabilities across glossary terms and languages. - Added extensive end-to-end Cypress tests covering glossary creation, editing, deletion, navigation, highlighting, and permissions. - Introduced feature flag support for the Glossary feature. - **Bug Fixes** - Improved API validation and error handling for glossary-related operations. - **Documentation** - Updated contributor guidelines with enhanced testing and translation key instructions. - **Tests** - Added comprehensive automated tests for glossary APIs, permissions, language endpoints, and UI components ensuring role-based access control and feature robustness. - **Chores** - Refined codebase with annotation updates, suppression of static analysis warnings, and minor refactoring for maintainability. - Updated API schema with glossary-related endpoints and models. - Improved type safety and component abstractions in frontend code. - Added React StrictMode wrapping for the app root. - Enhanced UI components with accessibility and styling improvements. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
…3060) Depends on #3003 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced annotation-based feature gating for API endpoints, allowing access to certain features only when enabled for the organization. - Added support for two new annotations: one requiring all specified features, and another requiring at least one of several features to be enabled. - **Refactor** - Replaced manual feature checks in multiple controllers with declarative annotations, simplifying code and centralizing feature enforcement. - **Tests** - Added comprehensive tests to verify correct enforcement of feature-based access controls. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Implements #2969 and #1418
Requires https://github.com/tolgee/translator/pull/32 to be deployed.
Expects these links to be valid documentation links:
Summary by CodeRabbit
New Features
Bug Fixes
Documentation
Tests
Chores